C#Union vs包含连续数据列表

G1x*_*b17 5 c# contains unions

我在查找一些问题的答案时遇到了一些麻烦,我已经解决了一些特定于我正在处理的代码的问题,而且我似乎无法找到关于Union如何在C#中使用它的核心机制的文档.所以问题是这个.

我有一组与此示例类似的数据:

     object[] someMainTypeArray = new object [n];
     List<object> objList2 = new List<object>();
     foreach ( object obj in someMainTypeArray ) {
        List<object> objList1 = new List<object>() { "1","2","3" };
        //each obj has a property that will generate a list of data
        //objList1 is the result of the data specific to obj
        //some of this data could be duplicates
        //Which is better, this:
        foreach ( object test in objList1 ) {
           if ( !objList2.Contains( test ) ) {
              objList2.Add( test );
           }
        }
        //or this:
        objList2 = objList2.Union( objList1 ).ToList();
        //Also, assume this has to happen anywhere from 0 to 60 times per second
     }
Run Code Online (Sandbox Code Playgroud)

让联盟完成所有工作更有效率吗?或者使用Contains比较每个元素是否更好?

如果两者都为"否",那么使用最少的处理时间填充唯一列表的最佳方法是什么?

效率是关键.此外,这不是家庭作业,或任何工作相关,只是学习相关.

这些列表在运行时是连续的,最终会被清理干净并重新填充.列表中的更改用于根据是否使用与此示例类似的最终结果列表来确定最终列表,如果该列表为空,则表示失败,并且该列表不是空的,它是一个成功的条件.

以下是创建的列表之一的代码片段:

     Player.ClearMoves();
     List<Pair<BoardLocation, BoardLocation>> attacking = new List<Pair<BoardLocation, BoardLocation>>();
     foreach ( ChessPiece p in Board[this.Player.Opponent] ) {
        if ( p.TheoryMove( this.Location ) ) {
           foreach ( Pair<BoardLocation , BoardLocation> l in Utility.GetLocations( p.Location , this.Location ) ) {
              if ( !attacking.Contains( l ) ) {
                 attacking.Add( l );
              }
           }
        }
     }
     if ( attacking.Count < 1 ) {
        return false;
     }
Run Code Online (Sandbox Code Playgroud)

pok*_*oke 9

您可以Enumerable.Union参考源中找到实现.

这是它的工作原理:

public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) {
    if (first == null) throw Error.ArgumentNull("first");
    if (second == null) throw Error.ArgumentNull("second");
    return UnionIterator<TSource>(first, second, null);
}

static IEnumerable<TSource> UnionIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
    Set<TSource> set = new Set<TSource>(comparer);
    foreach (TSource element in first)
        if (set.Add(element)) yield return element;
    foreach (TSource element in second)
        if (set.Add(element)) yield return element;
}
Run Code Online (Sandbox Code Playgroud)

如您所见,Union将遍历两个枚举并从这些源中生成对象.像所有Linq方法一样,它不会创建列表但是可以用作生成器函数.该列表仅在您致电时创建.ToList().

为了避免重复,它将使用a Set并尝试在产生元素之前添加元素.如果对集合的添加成功,则该元素尚未存在,因此可以产生.

请注意,集合非常有效,可以查找元素是否存在.它们以摊销的常数时间提供项目查找.所以这肯定比你objList2.Contains需要反复遍历列表以确定每个元素是否存在的效率更高.

还要注意,它Union是为了维护输入枚举的顺序而构建的.如果您不需要,那么您可以完全跳过这个并且Set首先使用a .如果您计划在重新使用结构时始终将新项目添加到同一目标集,那么这一点尤其有用:

HashSet<object> set = new HashSet<object>();

foreach (…)
{
    List<object> objList1 = …

    // expand the set with the items from `objList1`
    set.UnionWith(objList1);
}
Run Code Online (Sandbox Code Playgroud)

如果您首先避免创建objList1并直接将项目添加到集合中,那将会更好- 如果您的用例可以实现的话.