Search code examples
c#.netienumerable

Combine multiple collections into a collection of structs with Enumerable?


I have multiple arrays of objects: A, B ,C. They all have the same length.

I want to write a function that "merges" each element of the arrays to single elements in the resuling array.

An example:

(A[0] , B[0] , C[0]) => Result[0]

There is Enumerable.Join(), but my data is not keyed.


Solution

  • Are you looking for Zip? E.g. we can combine items into a named tuple:

    var result = A
      .Zip(B, (a, b) => (a, b))
      .Zip(C, (p, c) => (p.a, p.b, c));
    

    E.g.

    int[] A = { 1, 2, 3 };
    int[] B = { 4, 5, 6 };
    int[] C = { 7, 8, 9 };
    
    var result = A
      .Zip(B, (a, b) => (a, b))
      .Zip(C, (p, c) => (p.a, p.b, c));
    
    Console.WriteLine(string.Join(Environment.NewLine, result));
    

    Output:

    (1, 4, 7)
    (2, 5, 8)
    (3, 6, 9)
    

    If you have arbitrary number of arrays you can join items into enumeration of arrays:

    private static IEnumerable<T[]> ZipToArray<T>(params IEnumerable<T>[] sources) {
      if (sources is null)
        throw new ArgumentNullException(nameof(sources));
    
      var ens = sources
        .Select(source => source?.GetEnumerator())
        .ToArray();
    
      try {
        while (true) {
          foreach (var en in ens)
            if (!(en?.MoveNext() ?? true))
              yield break;
    
          yield return ens
            .Select(en => en is null ? default(T) : en.Current)
            .ToArray();
          }
      finally {
        foreach (var en in ens)
          en?.Dispose();
      }
    }
    

    E.g.

    int[] A = { 1, 2, 3 };
    int[] B = { 4, 5, 6 };
    int[] C = { 7, 8, 9 };
    
    int[][] result = ZipToArray(A, B, C).ToArray();