Merge multiple lists with variable length “popping” elements from each

后端 未结 7 788
被撕碎了的回忆
被撕碎了的回忆 2020-12-21 08:30

I\'d like to sort multiple lists (variable number of them) into single list, but keeping the specific order. For example:

List A: { 1,2,3,4,5 }
List B: { 6,7         


        
相关标签:
7条回答
  • 2020-12-21 08:47

    Here's a fairly simple way. It was fun to write up anyway.
    No, it isn't the best, but it works and you could expand it to suit your needs of using a List<List<int>> very easily.

    //Using arrays for simplicity, you get the idea.
    int[] A = { 1, 2, 3, 4, 5 };
    int[] B = { 6, 7, 8 };
    int[] C = { 9, 10, 11, 12 };
    
    List<int> ResultSet = new List<int>();
    
    //Determine this somehow. I'm doing this for simplicity.
    int longest = 5; 
    
    for (int i = 0; i < longest; i++)
    {
        if (i < A.Length)
            ResultSet.Add(A[i]);
        if (i < B.Length)
            ResultSet.Add(B[i]);
        if (i < C.Length)
            ResultSet.Add(C[i]);
    }
    
    //ResultSet contains: { 1, 6, 9, 2, 7, 10, 3, 8, 11, 4, 12, 5 }
    

    As you can see, just pop this out into a method and loop through your lists of lists, properly determining the max length of all lists.

    0 讨论(0)
  • 2020-12-21 08:48

    For more flexible use

     public static string MergeArrays(params IList<int>[] items)
        {
    
            var result = new List<int>();
            for (var i = 0; i < items.Max(x => x.Count); i++)
                result.AddRange(from rowList in items where rowList.Count > i select rowList[i]);
    
            return string.Join(",", result);
        }
    

    .

            var a = new List<int>() { 1, 2, 3, 4, 5 };
            var b = new List<int>() { 6, 7, 8 };
            var c = new List<int>() { 9, 10, 11, 12, 0, 2, 1 };
    
            var r = MergeArrays(a, b, c);
    
    0 讨论(0)
  • 2020-12-21 08:50

    There is no sense in over complicating this in my opinion, why not use a simple for loop to accomplish what you need?

    List<int> list1 = new List<int> { 1, 2, 3, 4, 5 };
    List<int> list2 = new List<int> { 6, 7, 8 };
    List<int> list3 = new List<int> { 9, 10, 11, 12 };
    List<int> resultList = new List<int>();
    
    for (int i = 0; i < list1.Count || i < list2.Count || i < list3.Count; i++)
    {
        if (i < list1.Count) resultList.Add(list1[i]);
        if (i < list2.Count) resultList.Add(list2[i]);
        if (i < list3.Count) resultList.Add(list3[i]);
    }
    

    Result: 1,6,9,2,7,10,3,8,11,4,12,5

    0 讨论(0)
  • 2020-12-21 08:51

    I'd go with:

    static void Main(string[] args)
    {
        var a = new List<int>() { 1, 2, 3, 4, 5 };
        var b = new List<int>() { 6, 7, 8 };
        var c = new List<int>() { 9, 10, 11, 12 };
    
        var abc = XYZ<int>(new[] { a, b, c }).ToList();
    }
    
    static IEnumerable<T> XYZ<T>(IEnumerable<IList<T>> lists)
    {
        if (lists == null)
            throw new ArgumentNullException();
        var finished = false;
        for (int index = 0; !finished; index++)
        {
            finished = true;
            foreach (var list in lists)
                if (list.Count > index) // list != null (prior checking for count)
                {
                    finished = false;
                    yield return list[index];
                }
        }
    }
    

    I had to use use IList to have indexer and Count. It doesn't creates anything (no enumerators, no lists, etc.), purely yield return.

    0 讨论(0)
  • 2020-12-21 08:53

    I suggest using IEnumerator<T> to enumerate lists while they have items:

    private static IEnumerable<T> Merge<T>(params IEnumerable<T>[] sources) {
      List<IEnumerator<T>> enums = sources
        .Select(source => source.GetEnumerator())
        .ToList();
    
      try {
        while (enums.Any()) {
          for (int i = 0; i < enums.Count;)
            if (enums[i].MoveNext()) {
              yield return enums[i].Current;
    
              i += 1;
            }
            else {
              // exhausted, let's remove enumerator
              enums[i].Dispose();
              enums.RemoveAt(i);
            }
        }
      }
      finally {
        foreach (var en in enums)
          en.Dispose();
      }
    }
    

    Test

    List<int> A = new List<int>() { 1, 2, 3, 4, 5 };
    List<int> B = new List<int>() { 6, 7, 8 };
    List<int> C = new List<int>() { 9, 10, 11, 12 };
    
    var result = Merge(A, B, C)
      .ToList();
    
    Console.Write(string.Join(", ", result));
    

    The outcome is

    1, 6, 9, 2, 7, 10, 3, 8, 11, 4, 12, 5
    
    0 讨论(0)
  • 2020-12-21 08:59

    For your problem I create static method, which can merge any collections as you want:

    public static class CollectionsHandling
    {
        /// <summary>
        /// Merge collections to one by index
        /// </summary>
        /// <typeparam name="T">Type of collection elements</typeparam>
        /// <param name="collections">Merging Collections</param>
        /// <returns>New collection {firsts items, second items...}</returns>
        public static IEnumerable<T> Merge<T>(params IEnumerable<T>[] collections)
        {
            // Max length of sent collections
            var maxLength = 0;
    
            // Enumerators of all collections
            var enumerators = new List<IEnumerator<T>>();
    
            foreach (var item in collections)
            {
                maxLength = Math.Max(item.Count(), maxLength);
                if(collections.Any())
                    enumerators.Add(item.GetEnumerator());
            }
            // Set enumerators to first item
            enumerators.ForEach(e => e.MoveNext());
    
            var result = new List<T>();
            for (int i = 0; i < maxLength; i++)
            {
                // Add elements to result collection
                enumerators.ForEach(e => result.Add(e.Current));
    
                // Remobve enumerators, in which no longer have elements
                enumerators = enumerators.Where(e => e.MoveNext()).ToList();
            }
    
            return result;
        }
    }
    

    Example of using:

    static void Main(string[] args)
    {
        var a = new List<int> { 1, 2, 3, 4, 5 };
        var b = new List<int> { 6, 7, 8 };
        var c = new List<int> { 9, 10, 11, 12 };
    
        var result= CollectionsHandling.Merge(a, b, c);
    }
    

    When you understand how it works, it will be possible to reduce the method of smaller.

    0 讨论(0)
提交回复
热议问题