繁体   English   中英

具有重复的两个列表的交集

[英]Intersection of two lists with repetitions

考虑到可能存在重复项,并且在输出中需要它们,因此我试图创建一个使两个列表相交的函数。

Console.Write((new[] {1, 2, 2, 3}).Intersect(new[] {1, 2, 2}));

仅输出{1,2},我需要的输出是{1,2,2}。

这是我创建的方法:

private static IEnumerable<int> IntersectWithRepetitons(List<int> a, List<int> b)
{
    if (!a.Any() || !b.Any()) return Enumerable.Empty<int>();
    if (a.Count() > b.Count()) return IntersectWithRepetitons(b, a);

    var idx = b.IndexOf(a.First());
    if (idx < 0) return IntersectWithRepetitons(b, a.Skip(1).ToList());

    var tmp1 = new List<int> { a.First() };
    var tmp2 = new List<int>(b);
    tmp2.RemoveAt(idx);
    return tmp1.Concat(IntersectWithRepetitons(tmp2, a.Skip(1).ToList()));
}

我确信这可以高度优化,但是,我主要关心的是(为了提高效率),为了保持输入列表完整无缺,当我从列表中删除找到的项目时,我必须复制“ b”列表:

var tmp2 = new List<int>(b);
tmp2.RemoveAt(idx);

每次递归调用都会发生这种情况。 任何想法或想法将不胜感激。 谢谢。

将其中一个序列映射到项的字典,以显示它们出现的次数,然后对另一个序列中的每个项(如果它在集合中)并且查找的值大于零,则将其屈服并递减:

public static IEnumerable<T> IntersectWithRepetitons<T>(this IEnumerable<T> first,
    IEnumerable<T> second)
{
    var lookup = second.GroupBy(x => x)
        .ToDictionary(group => group.Key, group => group.Count());
    foreach (var item in first)
        if (lookup.ContainsKey(item) && lookup[item] > 0)
        {
            yield return item;
            lookup[item]--;
        }
}

这样可以确保每次在两个集合中重复项目时,它们都是收益。

您可以使用TryGetValue删除一些字典查找,但是它牺牲了该方法的许多优点,因此我没有这么做。 如果您关心性能,那么更改并不是一件坏事。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM