简体   繁体   English

合并列表列表中的交叉项

[英]Merge intersecting items in a list of lists

I have list of lists where i would like to merge all lists which contain identical values and make a new list out of the merged lists using linq. 我有列表列表,我想合并所有包含相同值的列表,并使用linq从合并列表中创建一个新列表。 Here's and example: 这是和例子:

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}
   };

The desired output would be a new List<List<animal>> containing the following List<Animal> : 所需的输出将是包含以下List<Animal>的新List<List<animal>>

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

I'm rather new to linq and i got stuck at grouping the intersected lists without creating duplicates. 我对linq很陌生,而且我坚持将相交的列表分组而不创建重复项。

Here is the possible output with list of strings 这是带有字符串列表的可能输出

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

First, remember to override Equals and GetHahCode and/or implement IEquatable<Animal> in your Anymial class meaningfully(fe by comparing the Name). 首先,请记住重写EqualsGetHahCode和/或在Anymial类中有意义地实现IEquatable<Animal> (通过比较Name)。

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

Following extension method used which works with any type: 以下使用的扩展方法适用于任何类型:

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

Your question is vague one; 你的问题很模糊 ; in case you want to combine 0, 2, 4, ... 2n as well as 1, 3, 5, ... 2n - 1 lists and you are looking for Linq solution: 如果你想组合0, 2, 4, ... 2n以及1, 3, 5, ... 2n - 1列表,你正在寻找Linq解决方案:

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

Let's visualize the result : 让我们看看result

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

  Console.WritelLine(test);

Outcome 结果

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

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

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