合并列表列表中的交叉项

时间:2017-09-22 09:02:31

标签: c# .net list linq merge

我有列表列表,我想合并所有包含相同值的列表,并使用linq从合并列表中创建一个新列表。以下是示例:

var animalGroups = new List<List<Animal>>{    
    new List<Animal>{lizard,cat,cow,dog},
    new List<Animal>{horse, chicken, pig, turkey},
    new List<Animal>{ferret,duck,cat,parrot},
    new List<Animal>{chicken,sheep,horse,rabbit}
   };

所需的输出将是包含以下List<List<animal>>的新List<Animal>

{lizard, cat, cow, dog, ferret, duck, parrot} 
{horse,  chicken, pig, turkey, sheep, rabbit}

我对linq很陌生,而且我坚持将相交的列表分组而不会产生重复。

3 个答案:

答案 0 :(得分:1)

这是带有字符串列表的可能输出

    var animalGroups = new List<List<string>>
    {
        new List<string> {"lizard", "cat", "cow", "dog"},
        new List<string> {"horse", "chicken", "pig", "turkey"},
        new List<string> {"ferret", "duck", "cat", "parrot"},
        new List<string> {"chicken", "sheep", "horse", "rabbit"}
    };

    List<List<string>> mergedList = new List<List<string>>();
    for (int i = 0; i < animalGroups.Count; i++)
    {
        for (int j = i+1; j < animalGroups.Count; j++)
        {
            if (animalGroups[i].Intersect(animalGroups[j]).Any())
            {
                mergedList.Add(animalGroups[i].Concat(animalGroups[j]).Distinct().ToList());
            }
        }
    }

答案 1 :(得分:1)

首先,请务必有意义地覆盖EqualsGetHahCode和/或在IEquatable<Animal>类中实施Anymial(例如,通过比较名称)。

List<IEnumerable<Animal>> mergedLists = animalGroups.MergeIntersectingLists().ToList();

以下使用的扩展方法适用于任何类型:

public static IEnumerable<IEnumerable<T>> MergeIntersectingLists<T>(this IEnumerable<IEnumerable<T>> itemLists, IEqualityComparer<T> comparer = null) 
{
    if (comparer == null) comparer = EqualityComparer<T>.Default;

    var itemListDict = new Dictionary<T, HashSet<T>>(comparer);
    foreach (IEnumerable<T> sequence in itemLists)
    {
        IList<T> list = sequence as IList<T> ?? sequence.ToList();
        HashSet<T> itemStorage = null;
        list.FirstOrDefault(i => itemListDict.TryGetValue(i, out itemStorage));
        // FirstOrDefault will initialize the itemStorage because its an out-parameter
        bool partOfListIsContainedInOther = itemStorage != null;

        if (partOfListIsContainedInOther)
        {
            // add this list to the other storage (a HashSet that removes duplicates)
            foreach (T item in list)
                itemStorage.Add(item);
        }
        else
        {
            itemStorage = new HashSet<T>(list, comparer);
            // each items needs to be added to the dictionary, all have the same storage
            foreach (T item in itemStorage)
                itemListDict.Add(item, itemStorage); // same storage for all
        }
    }

    // Distinct removes duplicate HashSets because of reference equality
    //  needed because item was the key and it's storage the value
    //  and those HashSets are the same reference
    return itemListDict.Values.Distinct();  
}

答案 2 :(得分:0)

你的问题是模糊的一个;如果您想要合并number_of_cars以及0, 2, 4, ... 2n列表,并且您正在寻找 Linq 解决方案:

1, 3, 5, ... 2n - 1

让我们可视化 // I don't have Animal class, that's why I've put string // Be sure that Animal implements Equals as well as GetHashCode methods var animalGroups = new List<List<string>> { new List<string> {"lizard", "cat", "cow", "dog"}, new List<string> {"horse", "chicken", "pig", "turkey"}, new List<string> {"ferret", "duck", "cat", "parrot"}, new List<string> {"chicken", "sheep", "horse", "rabbit"} }; var result = animalGroups .Select((list, index) => new { list = list, index = index, }) .GroupBy(item => item.index % 2, // grouping 0, 2, ... 2n as well as 1, 3,... 2n - 1 item => item.list) .Select(chunk => chunk .SelectMany(c => c) .Distinct() .ToList()) .ToList();

result

结果

  string test = string.Join(Environment.NewLine, result
    .Select(list => string.Join(", ", list)));

  Console.WritelLine(test);