假设我有一个字符串列表:
A,B,C,d
然后是另一个字符串列表
B,C,d
我想知道第一个列表中哪些元素不在第二个列表中,因此结果将是A
我不知道扩展方法的名称是这样做的。我知道我可以使用concat,union,intersect进行类似的列表比较,但只是不知道完成这个特定任务的名称。
附录,我对重复项感兴趣,所以如果第一个列表是:
A,A,A,B,C,d
,第二个列表是
B,C,d
我想要
A,A,A
谢谢!
答案 0 :(得分:15)
您可以使用Except Extension Method获取列表中不在第二个列表中的所有元素:
var result = list1.Except(list2);
答案 1 :(得分:4)
var result = list1.Where(i => !list2.Contains(i));
答案 2 :(得分:4)
BCL中的“Except”方法会删除所有重复项,这不是您想要的。
如果问题中的列表很大,那么为了有效地执行此操作,您可能希望浪费内存以换取按时保存。类似的东西:
// yield all members of "sequence" omitting those in "except"
static IEnumerable<string> Filter(
this IEnumerable<string> sequence,
IEnumerable<string> except)
{
var set = new HashSet<string>(except); // Burn memory to save time
return from item in sequence
where !set.Contains(item)
select item;
}
这样,每次测试项目时都可以快速查找。
用
调用它var sequence = new List<string>() { A, B, A, C, D };
var except = new List<string>() { B, C };
var result = sequence.Filter(except).ToList();
答案 3 :(得分:0)
如果您对重复项的定义包括列表和,您希望有效地计算补充,那么您将需要使用不同的数据结构:一个包。包是一个允许重复的集合。
这是一个名为BagDifference
的扩展方法,可以有效地解决任何列表中的重复项以及受Eric回答的示例程序。
public class Bag<T> : Dictionary<T, int>
{
public Bag(IEnumerable<T> sequence)
{
foreach (var item in sequence)
{
if (!ContainsKey(item)) this[item] = 0;
++this[item];
}
}
}
public static class EnumerableExtensions
{
public static IEnumerable<T> BagDifference<T>(this IEnumerable<T> sequence1, IEnumerable<T> sequence2)
{
var bag1 = new Bag<T>(sequence1);
var bag2 = new Bag<T>(sequence2);
foreach (var item in bag1.Keys)
{
var count1 = bag1[item];
var count2 = bag2.ContainsKey(item) ? bag2[item] : 0;
var difference = Math.Max(0, count1 - count2);
for (int i = 0; i < difference; i++)
yield return item;
}
}
}
class Program
{
static void Main(string[] args)
{
var sequence = new List<string>() { "A", "B", "A", "C", "D" };
var except = new List<string>() { "A", "B", "C", "C" };
var difference = sequence.BagDifference(except).ToList();
}
}