在一个列表中查找不在另一个列表中的项目

时间:2019-09-05 17:52:58

标签: c# .net

我有2个对象列表,我想从第一个对象中获取所有对象,其中字符串a与第二个列表中的字符串a不匹配。

public class ObjectA  
{  
    string Item;  
    int b;  
}

public class ObjectB  
{  
    string Item;  
    int b;  
}

使用linq可以很容易地做到这一点,但是更快的方法是什么?

var newList = objectAList.Where(a => !objectBList.Any(b => b.Item == a.Item)).ToList()

5 个答案:

答案 0 :(得分:1)

这怎么办-没有linq,仍然不错且流利,为正确的类型进行了编辑:

ObjectBList.RemoveAll(p => ObjectAList.Find(p2 => p2.Item == p.Item) != null ? true : false);

完整示例:

public class ObjectBase {
    public string Item;
    public int b;
}

public class ObjectA : ObjectBase{ }

public class ObjectB : ObjectBase { }

public List<ObjectB> Testing() {
    var list1 = new List<ObjectA> { new ObjectA { Item = "str1", b = 0 } };
    var list2 = new List<ObjectB> { new ObjectB { Item = "str1", b = 0 }, new ObjectB { Item = "str2", b = 1 } };

    // Key Line - Remove all from list2 found in list1
    list2.RemoveAll(p => list1.Find(p2 => p2.Item == p.Item) != null ? true : false);

    return list2;
}

答案 1 :(得分:1)

Linq Except方法就是为此目的而设计的,并且速度非常快。但是,您会感到皱纹,您的两个类具有兼容的字段,但却是不同的对象。这是处理它的一种方法:

class ObjectBase
{
    public string Item;
    public int b;
}

class ObjectA : ObjectBase
{

}

class ObjectB : ObjectBase
{

}

class ObjectComparer : IEqualityComparer<ObjectBase>
{
    public bool Equals(ObjectBase a, ObjectBase b)
    {
        return a?.Item == b?.Item; 
    }
    public int GetHashCode(ObjectBase o)
    {
        return o.?Item?.GetHashCode() ?? 0;
    }
}

// Very fast compared to your current approach. 1000x for my test case.

var newList = objectAList.Except(objectBList, new ObjectComparer()).ToList();

答案 2 :(得分:0)

您可以尝试以下代码:

public static void Main(string[] args)
{
  List<ObjectA> listA = new List<ObjectA>()
  {
    new ObjectA(){Item = "abc" },
    new ObjectA(){Item = "ab" },
  };
  List<ObjectB> listB = new List<ObjectB>()
  {
    new ObjectB(){Item = "abc" },
  };
  // loop backwards removing entry if it is found in the other list
  for (int i = listA.Count - 1; i >= 0; i--)
    if (listB.Find(e => e.Item == listA[i].Item) != null)
      listA.RemoveAt(i);
}

我(您和我的)两种方法都运行了五次,并在毫秒内得到以下结果(每次循环重复算法,100000次迭代):

我的方法:107 46 94 67 91

您的方法:108267171138173

这也可能是由于额外的ToList()调用和创建新对象newList造成的。

因此,总而言之,如果有任何改进,那几乎没有什么改进,我不会为此而牺牲出色的LINQ方法提供的可读性。

此外,它们在内部被设计为尽可能快地工作,所以我会依靠它们:)

答案 3 :(得分:0)

最快的方法是:

var newList = objectAList.Select(a => a.Item).Except(objectBList.Select(b => b.Item));

是的,我知道这是Linq,但是您要求一种更快的方法:)

HTH

答案 4 :(得分:0)

时间上最快的方法是使用HashSet <>,尤其是对于大型列表:

    private List<ObjectA> Find(List<ObjectA> list1, List<ObjectB> list2)
    {
        var list2HashSet = list2.Select(x => x.Item).ToHashSet();
        return list1.Where(x => !list2HashSet.Contains(x.Item)).ToList();
    }

注意:,不要忘记将属性Item设为公开,否则它将无法正常工作!