两个列表的补充

本文关键字:列表 两个 | 更新日期: 2023-09-27 17:55:54

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

A,B,C,D

然后是另一个字符串列表

B,C,D

我想知道第一个列表中有哪些元素不在第二个列表中,所以结果将是

我不知道执行此操作的扩展方法的名称是什么。 我知道我可以使用 concat、union、intersect 进行类似的列表比较,但只是不知道完成此特定任务的名称。

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

A,A,A,B,C,D

第二个列表是

B,C,D

我想得到

,一,一

谢谢!

两个列表的补充

可以使用 Except 扩展方法获取列表中不在第二个列表中的所有元素:

var result = list1.Except(list2);
var result = list1.Where(i => !list2.Contains(i));

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();

如果你对重复项的定义包括两个列表,并且你想有效地计算补码,那么你需要使用不同的数据结构:一个包。 袋子是允许重复的套装。

这是一个称为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();
    }
}