加入两个不同长度的列表

时间:2018-11-06 09:34:38

标签: c# linq

我正在使用LINQ:

List<String> listA = new List<string>{"a", "b", "c", "d", "e", "f", "g"};  
List<String> listB = new List<string>{"1", "2", "3"};  

所需结果:

{"a", "1", "b", "2", "c", "3", "d", "1", "e", "2", "f", "3", "g", "1"}  

我尝试但失败了:

var mix = ListA.Zip(ListB, (l1, l2) => new[] { l1, l2 }).SelectMany(x => x);  
//Result : {"a", "1", "b", "2", "c", "3"}  

var mix = ListA.Zip(ListB, (a, b) => new[] { a, b })
        .SelectMany(x => x)
        .Concat(ListA.Count() < ListB.Count() ? ListB.Skip(ListA.Count()) : ListA.Skip(ListB.Count()))
        .ToList();  
//Result : {"a", "1", "b", "2", "c", "3", "d", "e", "f", "g"}  

如何使用LINQ做到这一点?

7 个答案:

答案 0 :(得分:9)

这行得通,即使我不确定为什么您需要它作为linq表达式:

var mix = Enumerable
           .Range(0, Math.Max(listA.Count, listB.Count))
           .Select(i => new[] { listA[i % listA.Count], listB[i % listB.Count] })
           .SelectMany(x => x);

答案 1 :(得分:2)

如何实施您自己的Zip版本?

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

namespace SO
{
    internal class Program
    {
        public static void Main(string[] args)
        {
            List<String> listA = new List<string> {"a", "b", "c", "d", "e", "f", "g"};
            List<String> listB = new List<string> {"1", "2", "3"};

            var mix = listA.ZipNew(listB, (l1, l2) => new[] {l1, l2}).SelectMany(x => x);

            foreach (var m in mix)
            {
                Console.WriteLine(m);
            }
        }
    }

    public static class Impl
    {
        public static int A(this int a)
        {
            return 1;
        }

        public static IEnumerable<TResult> ZipNew<TFirst, TSecond, TResult>( 
            this IEnumerable<TFirst> first, 
            IEnumerable<TSecond> second, 
            Func<TFirst, TSecond, TResult> resultSelector) 
        { 
            using (IEnumerator<TFirst> iterator1 = first.GetEnumerator()) 
            using (IEnumerator<TSecond> iterator2 = second.GetEnumerator())
            {
                var i1 = true;
                var i2 = true;
                var i1Shorter = false;
                var i2Shorter = false;
                var firstRun = true;


                while(true) 
                {
                    i1 = iterator1.MoveNext();
                    i2 = iterator2.MoveNext();

                    if (!i1 && (i1Shorter || firstRun))
                    {
                        iterator1.Reset();
                        i1 = iterator1.MoveNext();
                        i1Shorter = true;
                        firstRun = false;
                    }

                    if (!i2 && (i2Shorter || firstRun))
                    {
                        iterator2.Reset();
                        i2 = iterator2.MoveNext();
                        i2Shorter = true;
                        firstRun = false;
                    }

                    if (!(i1 && i2))
                    {
                        break;
                    }

                    yield return resultSelector(iterator1.Current, iterator2.Current); 
                }
            } 
        }
    }
}

答案 2 :(得分:2)

到目前为止,只有一种版本尝试做正确的事情并使用正确的方法,这是BWA提出的版本。可以对此扩展进行一些简化,因此我将其留在此处以供参考:

public static IEnumerable<TResult> ZipLoop<TFirst, TSecond, TResult>(
    this IEnumerable<TFirst> first,
    IEnumerable<TSecond> second,
    Func<TFirst, TSecond, TResult> resultSelector)
{
    if (first is null) throw new ArgumentNullException(nameof(first));
    if (second is null) throw new ArgumentNullException(nameof(second));
    if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector));

    var (firstCycle, secondCycle) = (false, false);

    var e1 = first.GetEnumerator();
    var e2 = second.GetEnumerator();
    try
    {
        while (true)
        {
            if (!TryMoveNextOrLoop(first, ref e1, ref firstCycle)) yield break;
            if (!TryMoveNextOrLoop(second, ref e2, ref secondCycle)) yield break;
            if (firstCycle && secondCycle) yield break;
            yield return resultSelector(e1.Current, e2.Current);
        }
    }
    finally
    {
        e1?.Dispose();
        e2?.Dispose();
    }
}

private static bool TryMoveNextOrLoop<T>(IEnumerable<T> source, ref IEnumerator<T> enumerator, ref bool cycle)
{
    if (!enumerator.MoveNext())
    {
        cycle = true;
        enumerator.Dispose();
        enumerator = source.GetEnumerator();
        return enumerator.MoveNext();           
    }
    return true;
}

答案 3 :(得分:0)

您非常接近(一个)答案。怎么样?

var listA = new List<string> { "a", "b", "c", "d", "e", "f", "g" };
var listB = new List<string> { "1", "2", "3" };

// "a", "b", "c", "d", "e", "f", "g", "a", "b", "c", "d", "e", "f", "g", etc.
// This is lazily evaluated so it doesn't matter that there are
// more elements than needed here.
var repeatedA = Enumerable.Repeat(listA, listB.Count)
    .SelectMany(list => list);

// "1", "2", "3", "1", "2", "3", etc. This is lazily evaluated
// so it doesn't matter that there are more elements than needed here.
var repeatedB = Enumerable.Repeat(listB, listA.Count)
    .SelectMany(list => list);

var result = repeatedA.Zip(repeatedB, (a, b) => new[] { a, b })
    .SelectMany(x => x)
    .Take(2 * Math.Max(listA.Count, listB.Count));

// result is {"a", "1", "b", "2", "c", "3", "d", "1", "e", "2", "f", "3", "g", "1"}  

答案 4 :(得分:0)

我会采用List<String> listA = new List<string> { "a", "b", "c", "d", "e", "f", "g" }; List<String> listB = new List<string> { "1", "2", "3" }; List<string> listC = new List<string>(); for (int i = 0; i < Math.Max(listA.Count, listB.Count); i++) { listC.Add(listA[i % listA.Count]); listC.Add(listB[i % listB.Count]); } 循环方法

handleResize = e => {
  if (this.state.navHidden === false && window.outerWidth > 500) {
    this.setState({ hidden: true })
  } else if (this.state.navHidden === true && window.outerWidth <= 500) {
    this.setState({ hidden: false })
  }
}

答案 5 :(得分:0)

如何?

listA.SelectMany((a, i) => new[] { a, listB[i % listB.Count]})

答案 6 :(得分:-1)

尝试一下...

var mix =Enumerable.Range(0, new[] { listA.Count, listB.Count }.Max()).Select(i => new[] { listA[i % listA.Count], listB[i % listB.Count] }).SelectMany(x => x);