I am using LINQ:
List<String> listA = new List<string>{"a", "b", "c", "d", "e", "f", "g"};
List<String> listB = new List<string>{"1", "2", "3"};
Desired result:
{"a", "1", "b", "2", "c", "3", "d", "1", "e", "2", "f", "3", "g", "1"}
I tried but fail:
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"}
How can I do this using LINQ?
chain() + zip() zip() can be used to link both the lists and then chain() can used to perform the alternate append of the elements as desired.
To interleave multiple lists of the same length in Python, we can use list comprehension and zip . We have 3 lists l1 , l2 , and l3 . And then we put them into the lists list. Then to interleave all the lists, we call zip with all the lists in lists as arguments.
This works, even if I am not sure why you need it as linq expression:
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);
And how about implement your own wersion of 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);
}
}
}
}
}
There is only version that tries to do the right thing and uses the right approach so far and it's the one by BWA. This can be simplified a little bit to this extension so I'll leave it here for reference:
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;
}
I would go with the for
loop approach
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]);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With