簡體   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