两个列表的补充?

时间:2011-05-09 15:55:49

标签: c# extension-methods

假设我有一个字符串列表:

A,B,C,d

然后是另一个字符串列表

B,C,d

我想知道第一个列表中哪些元素不在第二个列表中,因此结果将是A

我不知道扩展方法的名称是这样做的。我知道我可以使用concat,union,intersect进行类似的列表比较,但只是不知道完成这个特定任务的名称。

附录,我对重复项感兴趣,所以如果第一个列表是:

A,A,A,B,C,d

,第二个列表是

B,C,d

我想要

A,A,A

谢谢!

4 个答案:

答案 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();
    }
}