Keegan
Keegan

Reputation: 23

C# LINQ Zipping 2 list of lists based on uniqueness of objects

I am trying to zip 2 lists of lists of objects - only where the resulting zipped list would contain lists of distinct objects (list 2's lists sometimes have duplicate objects when compared to list 1). The count of objects in the resultant list must be maintained, meaning we can't have lists of differing sizes. The number of lists in list 1 is greater the number in list 2. Which would mean repeatedly going through list 2 when zipping.

The above is represented using loops below. Is this possible using only linq?

//this list of list contains the larger number of elements to which the 2nd list of list needs to be joined
List<List<object>> FullList = new List<List<object>>(); //is not empty - instantiated with some list

//2nd list of list - contains duplicates of the 1st list in terms of the objects in the underlying list
List<List<object>> comboBaseList = new List<List<object>>(); //is not empty - instantiated with some list
List<List<object>> comboList = comboBaseList;

//need to zip lists where there are no duplicate objects in the 2nd list's list, the count of the 1st list of list remains the same as FullList
List<List<object>> finalList = new List<List<object>>(); //empty - meant to hold final combined list

int i = 0;

foreach iList in FullList
{
    if (i < comboList.count)
    {
        while (iList.Select(x => x.Id).Contains(comboList[i].Select(y => y.Id)))
        {
            i += 1;
        }
        finalList.Add(iList.Zip(comboList[i], (x, y) => x.Union(y))); //**CAN WE BYPASS THE LOOPS AND JUST USE LINQ?
        comboList.RemoveAt(i);
        i = 0;
    }
    else
    {
        comboList = comboBaseList;
        i = 0;
    }
}

To simplify the data I'll use lists of lists of integers - which could be the Id's of the objects in my case

FullList = 
(
{1,2,3},
{2,5,6},
{7,8,9}
)

comboList = 
(
{2,5},
{8,9}
)

I want to zip the above lists to yield the resultant as below - Note that there are 3 results as per FullList and the undelying lists have distinct integers

finalList =
{
 {1,2,3,8,9},
 {2,5,6,8,9},
 {7,8,9,2,5}
}

Upvotes: 0

Views: 421

Answers (2)

Jon Skeet
Jon Skeet

Reputation: 1499870

Okay, it sounds like you might want something like:

var result = fullList
    .Select(original =>
       // We want the original sublist...
       original
           // concatenated with...
           .Concat(
           // ... any comboList element
           comboList
               // which is completely distinct from "original"
               .Where(cl => !original.Intersect(cl).Any())
               // ... flattening all such comboLists
               .SelectMany(cl => cl))
           .ToList())
    .ToList();

Here's a complete example:

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        var fullList = new[]
        {
            new[] { 1, 2, 3 },
            new[] { 2, 5, 6 },
            new[] { 7, 8, 9 }
        };

        var comboList = new[]
        {
            new[] { 2, 5 },
            new[] { 8, 9 }
        };

        var result = MergeCombinations(fullList, comboList);
        foreach (var item in result)
        {
            Console.WriteLine(string.Join(", ", item));
        }
    }

    static List<List<T>> MergeCombinations<T>(
        IEnumerable<IEnumerable<T>> fullList,
        IEnumerable<IEnumerable<T>> comboList)
    {
        var result = fullList
            .Select(original =>
                // We want the original sublist...
                original
                    // concatenated with...
                    .Concat(
                    // ... any comboList element
                       comboList
                           // which is completely distinct from "original"
                           .Where(cl => !original.Intersect(cl).Any())
                           // ... flattening all such comboLists
                          .SelectMany(cl => cl))
                   .ToList())
             .ToList();
        return result;
    }                                           
}

Upvotes: 1

user3041160
user3041160

Reputation: 684

var fullList = new List<List<int>>()
        {
            new List<int>() {1,2,3},
            new List<int>() {2,5,6},
            new List<int>() {7,8,9}
        };

 var comboList = new List<List<int>>()
        {
            new List<int>() {2,5},
            new List<int>() {8,9},
        };


fullList.ForEach(i =>
        {
            comboList.ForEach(j =>
            {
                if (i.All(x => !j.Contains(x)))
                {
                    i.AddRange(j);
                    return;
                };
            });
        });

Upvotes: 0

Related Questions