两个列表的补充
本文关键字:列表 两个 | 更新日期: 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();
}
}