Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have a List contains arrays in various sizes. For example:
0 and 7. arrrays have same data {1,2,3,4,5,6}
2, 4 and 5. arrays have same data {1,2,3}
Attention! 3 and 6 doesn't have same data [3] = {1,2} , [6] = {1,3}
I want to get which indexes have same data and add this indexes to another List. For example
anotherList[ 0 ] = {0,7}
anotherList[ 1 ] = {2,4,5}
How can I do this?
Thanks in advance.
You can use this code (Linq i.e. SequenceEqual is very helpful here):
private static IList<IList<int>> EqualArrays(List<int[]> list) {
IList<IList<int>> result = new List<IList<int>>();
HashSet<int> proceeded = new HashSet<int>();
for (int i = 0; i < list.Count; ++i) {
if (proceeded.Contains(i))
continue;
int[] item = list[i];
List<int> equals = new List<int>() { i };
result.Add(equals);
for (int j = i + 1; j < list.Count; ++j)
if (item.SequenceEqual(list[j])) {
equals.Add(j);
proceeded.Add(j);
}
}
return result;
}
...
// Your test case:
List<int[]> list = new List<int[]>() {
new int[] {1, 2, 3, 4, 5, 5, 7},
new int[] {1},
new int[] {1, 2, 3},
new int[] {1, 2},
new int[] {1, 2, 3},
new int[] {1, 2, 3},
new int[] {1, 3},
new int[] {1, 2, 3, 4, 5, 5, 7}
};
// anotherList == {{0, 7}, {1}, {2, 4, 5}, {3}, {6}}
IList<IList<int>> anotherList = EqualArrays(list);
Try this
List<byte[]> anotherList = new List<byte[]>();
foreach (byte[] array in list2)
if (!list1.Any(a => a.SequenceEqual(array)))
anotherList.Add(array);
int[][] original =
{
new [] {1,2,3,4,5,6},
new [] {1},
new [] {1,2,3},
new [] {1,2},
new [] {1,2,3},
new [] {1,2,3},
new [] {1,3},
new [] {1,2,3,4,5,6},
};
int[][] anotherList =
original.Select((values, index) => new { values, index })
.GroupBy(x => x.values, SequenceComparer<int>.Default)
.Where(grouping => grouping.Count() > 1) // optional
.Select(grouping => grouping.Select(x => x.index).ToArray())
.ToArray();
I've adapted the definition for SequenceComparer<T> from here (and here):
public class SequenceComparer<T> : IEqualityComparer<IEnumerable<T>>
{
public static readonly SequenceComparer<T> Default = new SequenceComparer<T>();
public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
{
if (Object.ReferenceEquals(x, y))
return true;
return x != null && y != null && x.SequenceEqual(y);
}
public int GetHashCode(IEnumerable<T> seq)
{
if (seq == null)
return 0;
unchecked
{
const int p = 16777619;
const int hash = (int)2166136261;
return seq.Select(e => e.GetHashCode())
.Aggregate(hash, (a, b) => (a ^ b) * p));
}
}
}
Related
got this little problem in my little C# hobby project that I can't quite work out. I have been stuck in lots of messy and complicated nested loops. Hope someone can give light.
I have a list of list of int, i.e. List<List<int>> . Assume each list of int contains unique items. The minimum size of the list is 5. I need to find exactly two lists of int (List A and List B) that share exactly three common items and another list of int (List X) that contains exactly one of these common items. Another condition must hold: none of the other lists contain any of these three items.
For example:
List<List<int>> allLists = new List<List<int>>();
allLists.Add(new List<int>() {1, 2, 3, 4});
allLists.Add(new List<int>() {1, 2});
allLists.Add(new List<int>() {3, 4});
allLists.Add(new List<int>() {3, 4, 5, 6, 7, 8, 9});
allLists.Add(new List<int>() {4, 6, 8});
allLists.Add(new List<int>() {5, 7, 9, 11});
allLists.Add(new List<int>() {6, 7, 8});
For the above example, I would hope to find a solution as:
ListA and ListB: [3, 5] // indices of allLists
ListX: 6 // index of allLists
The three shared items: [5, 7, 9]
The matching item in ListX: 7
Note: Depending on the content of lists, there may be multiple solutions. There may be also situations that no lists is found matching the above conditions.
I was stuck in some messy nested loops. I was thinking if anyone may come up with a simple and efficient solution (possibly with LINQ?)
Originally I had something stupid like the following:
for (var i = 0; i < allLists.Count - 1; i++)
{
if (allLists[i].Count > 2)
{
for (var j = i + 1; j < allLists.Count; j++)
{
List<int> sharedItems = allLists[i].Intersect(allLists[j]).ToList();
if (sharedItems.Count == 3)
{
foreach (var item in sharedItems)
{
int itemCount = 0;
int? possibleListXIndex = null;
for (var k = 0; k < allLists.Count; k++)
{
if (k != i && k != j && allLists[k].Contains(item))
{
// nested loops getting very ugly here... also not sure what to do....
}
}
}
}
}
}
}
Extended Problem
There is an extended version of this problem in my project. It is in the same fashion:
find exactly three lists of int (List A, List B and List C) that share exactly four common items
find another list of int (List X) that contains exactly one of the above common items
none of the other lists contain these four items.
I was thinking the original algorithm may become scalable to also cover the extended version without having to write another version of algorithm from scratch. With my nested loops above, I think I will have no choice but to add at least two deeper-level loops to cover four items and three lists.
I thank everyone for your contributions in advance! Truly appreciated.
Here's a solution that comes up with your answer. I wouldn't exactly called it efficient, but it's pretty simple to follow.
It breaks the work in two step. First it constructs a list of initial candidates where they have exactly three matches. The second step adds the ListX property and checks to see if the remaining criteria is met.
var matches = allLists.Take(allLists.Count - 1)
.SelectMany((x, xIdx) => allLists
.Skip(xIdx + 1)
.Select(y => new { ListA = x, ListB = y, Shared = x.Intersect(y) })
.Where(y => y.Shared.Count() == 3))
.SelectMany(x => allLists
.Where(y => y != x.ListA && y != x.ListB)
.Select(y => new
{
x.ListA,
x.ListB,
x.Shared,
ListX = y,
SingleShared = x.Shared.Intersect(y)
})
.Where(y => y.SingleShared.Count() == 1
&& !allLists.Any(z => z != y.ListA
&& z != y.ListB
&& z != y.ListX
&& z.Intersect(y.Shared).Any())));
You get the output below after running the following code.
ListA. 3: [3, 4, 5, 6, 7, 8, 9] ListB. 5: [5, 7, 9, 11] => [5, 7, 9], ListX. 6:[6, 7, 10] => 7
matches.ToList().ForEach(x => {
Console.WriteLine("ListA. {0}: [{1}] ListB. {2}: [{3}] => [{4}], ListX. {5}:[{6}] => {7}",
allLists.IndexOf(x.ListA),
string.Join(", ", x.ListA),
allLists.IndexOf(x.ListB),
string.Join(", ", x.ListB),
string.Join(", ", x.Shared),
allLists.IndexOf(x.ListX),
string.Join(", ", x.ListX),
string.Join(", ", x.SingleShared));
I will leave the exercise of further work such as which list matches which other one given your fairly generic requirement. So here, I find those that match 3 other values in a given array, processing all arrays - so there are duplicates here where an A matches a B and a B matches an A for example.
This should give you something you can work from:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
var s = new List<int>();
List<List<int>> allLists = new List<List<int>>();
allLists.Add(new List<int>()
{1, 2, 3, 4});
allLists.Add(new List<int>()
{1, 2});
allLists.Add(new List<int>()
{3, 4});
allLists.Add(new List<int>()
{3, 4, 5, 6, 7, 8, 9});
allLists.Add(new List<int>()
{4, 6, 8});
allLists.Add(new List<int>()
{5, 7, 9, 11});
allLists.Add(new List<int>()
{6, 7, 8});
/*
// To iterate over it.
foreach (List<int> subList in allLists)
{
foreach (int item in subList)
{
Console.WriteLine(item);
}
}
*/
var countMatch = 3;
/* iterate over our lists */
foreach (var sub in allLists)
{
/* not the sub list */
var ns = allLists.Where(g => g != sub);
Console.WriteLine("Check:{0}", ns.Count()); // 6 of the 7 lists so 6 to check against
//foreach (var glist in ns) - all of them, now refactor to filter them:
foreach (var glist in ns.Where(n=> n.Intersect(sub).Count() == countMatch))
{
var r = sub.Intersect(glist); // get all the matches of glist and sub
Console.WriteLine("Matches:{0} in {1}", r.Count(), glist.Count());
foreach (int item in r)
{
Console.WriteLine(item);
}
}
}
}
}
This will output this:
Hello World
Check:6
Check:6
Check:6
Check:6
Matches:3 in 3
4
6
8
Matches:3 in 4
5
7
9
Matches:3 in 3
6
7
8
Check:6
Matches:3 in 7
4
6
8
Check:6
Matches:3 in 7
5
7
9
Check:6
Matches:3 in 7
6
7
8
I think it would be better to break this functionality into several methods, then it will look easier to read.
var allLists = new List<List<int>>();
allLists.Add(new List<int>() {1, 2, 3, 4});
allLists.Add(new List<int>() {1, 2});
allLists.Add(new List<int>() {3, 4});
allLists.Add(new List<int>() {3, 4, 5, 6, 7, 8, 9});
allLists.Add(new List<int>() {4, 6, 8});
allLists.Add(new List<int>() {5, 7, 9, 11});
allLists.Add(new List<int>() {6, 7, 8});
var count = allLists.Count;
for (var i = 0; i < count - 1; i++)
{
var left = allLists[i];
if (left.Count > 2)
{
for (var j = i + 1; j < count; j++)
{
var right = allLists[j];
var sharedItems = left.Intersect(right).ToList();
if (sharedItems.Count == 3)
{
for (int k = 0; k < count; k++)
{
if (k == i || k == j)
continue;
var intersected = allLists[k].Intersect(sharedItems).ToList();
if (intersected.Count == 1)
{
Console.WriteLine($"Found index k:{k},i:{i},j:{j}, Intersected numbers:{string.Join(",",intersected)}");
}
}
}
}
}
}
I just thought if I try to find the item in List X first, I might need fewer loops in practice. Correct me if I am wrong.
public static void match(List<List<int>> allLists, int numberOfMainListsToExistIn, int numberOfCommonItems)
{
var possibilitiesToCheck = allLists.SelectMany(i => i).GroupBy(e => e).Where(e => (e.Count() == numberOfMainListsToExistIn + 1));
foreach (var pGroup in possibilitiesToCheck)
{
int p = pGroup.Key;
List<int> matchingListIndices = allLists.Select((l, i) => l.Contains(p) ? i : -1).Where(i => i > -1).ToList();
for (int i = 0; i < matchingListIndices.Count; i++)
{
int aIndex = matchingListIndices[i];
int bIndex = matchingListIndices[(i + 1) % matchingListIndices.Count];
int indexOfListXIndex = (i - 1 + matchingListIndices.Count) % matchingListIndices.Count;
int xIndex = matchingListIndices[indexOfListXIndex];
IEnumerable<int> shared = allLists[aIndex].Intersect(allLists[bIndex]).OrderBy(e => e);
IEnumerable<int> xSingle = shared.Intersect(allLists[xIndex]);
bool conditionsHold = false;
if (shared.Count() == numberOfCommonItems && xSingle.Count() == 1 && xSingle.Contains(p))
{
conditionsHold = true;
for (int j = 2; j < matchingListIndices.Count - 1; j++)
{
int cIndex = matchingListIndices[(i + j) % matchingListIndices.Count];
if (!Enumerable.SequenceEqual(shared, allLists[aIndex].Intersect(allLists[cIndex]).OrderBy(e => e)))
{
conditionsHold = false;
break;
}
}
if (conditionsHold)
{
List<int> theOtherListIndices = Enumerable.Range(0, allLists.Count - 1).Except(matchingListIndices).ToList();
if (theOtherListIndices.Any(x => shared.Intersect(allLists[x]).Count() > 0))
{
conditionsHold = false;
}
}
}
if (conditionsHold)
{
matchingListIndices.RemoveAt(indexOfListXIndex);
Console.Write("List A and B: {0}. ", String.Join(", ", matchingListIndices));
Console.Write("Common items: {0}. ", String.Join(", ", shared));
Console.Write("List X: {0}.", xIndex);
Console.WriteLine("Common item in list X: {0}. ", p);
}
}
}
}
For the above example, I will just call the method like this:
match(allLists, 2, 3);
This method will also work with the extended problem:
match(allLists, 3, 4);
... and even more if the problem is even further more extended to (4, 5) and so on...
I have two C# Lists of different sizes e.g.
List<int> list1 = new List<int>{1,2,3,4,5,6,7};
List<int> list2 = new List<int>{4,5,6,7,8,9};
I want to use the linq Zip method to combine these two into a list of tuples that is of the size list1. Here is the resulting list I am looking for
{(1,4), (2,5), (3,6), (4,7), (5,8), (6,9), (7,0)} //this is of type List<(int,int)
Since the last item of list1 does not has a counterpart in list2, I fill up my last item of the resulting list with a default value (in this case 0 as in my case it will never appear in any of the original lists).
Is there a way I can use the linq Zip method alone to achieve this?
You can use Concat to make them both the same size, and then zip it:
var zipped = list1.Concat(Enumerable.Repeat(0,Math.Max(list2.Count-list1.Count,0)))
.Zip(list2.Concat(Enumerable.Repeat(0,Math.Max(list1.Count-list2.Count,0))),
(a,b)=>(a,b));
Or create an extension method:
public static class ZipExtension{
public static IEnumerable<TResult> Zip<TFirst,TSecond,TResult>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst,TSecond,TResult> func,
TFirst padder1,
TSecond padder2)
{
var firstExp = first.Concat(
Enumerable.Repeat(
padder1,
Math.Max(second.Count()-first.Count(),0)
)
);
var secExp = second.Concat(
Enumerable.Repeat(
padder2,
Math.Max(first.Count()-second.Count(),0)
)
);
return firstExp.Zip(secExp, (a,b) => func(a,b));
}
}
So you can use like this:
//last 2 arguments are the padder values for list1 and list2
var zipped = list1.Zip(list2, (a,b) => (a,b), 0, 0);
There is a useful and popular MoreLinq library. Install it and use.
using MoreLinq;
var result = list1.ZipLongest(list2, (x, y) => (x, y));
Try this using Zip function-
static void Main(string[] args)
{
List<int> firstList = new List<int>() { 1, 2, 3, 4, 5, 6, 0, 34, 56, 23 };
List<int> secondList = new List<int>() { 4, 5, 6, 7, 8, 9, 1 };
int a = firstList.Count;
int b = secondList.Count;
for (int k = 0; k < (a - b); k++)
{
if(a>b)
secondList.Add(0);
else
firstList.Add(0);
}
var zipArray = firstList.Zip(secondList, (c, d) => c + " " + d);
foreach(var item in zipArray)
{
Console.WriteLine(item);
}
Console.Read();
}
Or you can try this using ZipLongest Function by installing MoreLinq nuget package-
static void Main(string[] args)
{
List<int> firstList = new List<int>() { 1, 2, 3, 4, 5, 6, 0, 34, 56, 23 };
List<int> secondList = new List<int>() { 4, 5, 6, 7, 8, 9, 1 };
var zipArray = firstList.ZipLongest(secondList, (c, d) => (c,d));
foreach (var item in zipArray)
{
Console.WriteLine(item);
}
Console.Read();
}
Try this code-
static void Main(string[] args)
{
List<int> firstList=new List<int>() { 1, 2, 3, 4, 5, 6,0,34,56,23};
List<int> secondList=new List<int>() { 4, 5, 6, 7, 8, 9,1};
int a = firstList.Count;
int b = secondList.Count;
if (a > b)
{
for(int k=0;k<(a-b);k++)
secondList.Add(0);
}
else
{
for (int k = 0; k < (b-a); k++)
firstList.Add(0);
}
for(int i=0;i<firstList.Count;i++)
{
for(int j=0;j<=secondList.Count;j++)
{
if(i==j)
Console.Write($"({Convert.ToInt32(firstList[i])},{ Convert.ToInt32(secondList[j])})" + "");
}
}
Console.Read();
}
I want to find the index of sublist in list route which contains certain value(i), but I don't want to make a class of it.
Here is my code:
var route = new List<List<int>>();
for (int i = 0; i<DC1; ++i)
{
for (int j = 0; j<DC1; ++j)
{
if (routeopt.x[0, j] == 1)
{
List<int> subroute = new List<int>();
if (routeopt.x[i, j] == 1)
{
subroute.Add(j);
route.Add(subroute);
}
}
}
if(i == 0) continue;
for (int j = 1; j<DC1;j++ )
{
if (routeopt.x[i, j] == 1)
route[route.IndexOf(i)].Add ( j);
}
}
foreach (var subroute in route)
{
Console.Write("subroute: ");
foreach (int s in subroute)
Console.Write(s + " ");
Console.WriteLine();
}
For example, based on this code:
for (int j = 1; j < DC1;j++ )
{
if (routeopt.x[i, j] == 1)
route[route.IndexOf(i)].Add(j);
}
I want to make if x[1,3] == 1 then I can add 3 to sublist which contains 1.
this code route.IndexOf(i) is still get red underline, please help how to correct it. Thanks
You can use LINQ's Single method to retrieve the specific list you want given a predicate Contains(i). Here I am looking for the list that contains 6, and adds 7 to it.
var routes = new List<List<int>>()
{
new List<int>() {1, 2, 3},
new List<int>() {4, 5, 6},
};
List<int> targetList = routes.Single(i => i.Contains(6));
targetList.Add(7);
To get specifically the index of that list, then you can use IndexOf method like:
int targetListIndex = routes.IndexOf(targetList); // 1 in this example
Let's start from an example (which we turn into a test later):
List<List<int>> route = new List<List<int>>() {
new List<int>() {1, 2, 3, 4, 5}, // sublist #0: contains value == 4
new List<int>() {7, 8, 2, 9}, // sublist #1: doesn't contain value == 4
new List<int>() {9, 10, 4}, // sublist #2: contains value == 4
};
and we are looking for value within each of sublists
int value = 4;
finally, we want to have sublist indexes as the outcome: 0 and 2.
If it's your case, I suggest using Linq
List<List<int>> route = new List<List<int>>() {
new List<int>() {1, 2, 3, 4, 5},
new List<int>() {7, 8, 2, 9},
new List<int>() {9, 10, 4},
};
int value = 4;
var indexesFound = route
.Select((sublist, index) => new { // eh, new class, but anonymous one
sublist = sublist,
index = index, })
.Where(chunk => chunk.sublist.Contains(value))
.Select(chunk => chunk.index)
.ToArray(); // if you want, say, array materialization
Test
Console.Wrire(string.Join(", ", indexesFound));
Outcome:
0, 2
Edit: if you want to have just one index, you have to specify which one, e.g. for the very first index put .First() instead of .ToArray():
int firstIndexFound = route
.Select((sublist, index) => new { // eh, new class, but anonymous one
sublist = sublist,
index = index, })
.Where(chunk => chunk.sublist.Contains(value))
.Select(chunk => chunk.index)
.First(); // or .Last()
Assuming I have a list
var listOfInt = new List<int> {1, 2, 3, 4, 7, 8, 12, 13, 14}
How can I use LINQ to obtain a list of lists as follows:
{{1, 2, 3, 4}, {7, 8}, {12, 13, 14}}
So, i have to take the consecutive values and group them into lists.
You can create extension method (I omitted source check here) which will iterate source and create groups of consecutive items. If next item in source is not consecutive, then current group is yielded:
public static IEnumerable<List<int>> ToConsecutiveGroups(
this IEnumerable<int> source)
{
using (var iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
{
yield break;
}
else
{
int current = iterator.Current;
List<int> group = new List<int> { current };
while (iterator.MoveNext())
{
int next = iterator.Current;
if (next < current || current + 1 < next)
{
yield return group;
group = new List<int>();
}
current = next;
group.Add(current);
}
if (group.Any())
yield return group;
}
}
}
Usage is simple:
var listOfInt = new List<int> { 1, 2, 3, 4, 7, 8, 12, 13, 14 };
var groups = listOfInt.ToConsecutiveGroups();
Result:
[
[ 1, 2, 3, 4 ],
[ 7, 8 ],
[ 12, 13, 14 ]
]
UPDATE: Here is generic version of this extension method, which accepts predicate for verifying if two values should be considered consecutive:
public static IEnumerable<List<T>> ToConsecutiveGroups<T>(
this IEnumerable<T> source, Func<T,T, bool> isConsequtive)
{
using (var iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
{
yield break;
}
else
{
T current = iterator.Current;
List<T> group = new List<T> { current };
while (iterator.MoveNext())
{
T next = iterator.Current;
if (!isConsequtive(current, next))
{
yield return group;
group = new List<T>();
}
current = next;
group.Add(current);
}
if (group.Any())
yield return group;
}
}
}
Usage is simple:
var result = listOfInt.ToConsecutiveGroups((x,y) => (x == y) || (x == y - 1));
This works for both sorted and unsorted lists:
var listOfInt = new List<int> { 1, 2, 3, 4, 7, 8, 12, 13 };
int index = 0;
var result = listOfInt.Zip(listOfInt
.Concat(listOfInt.Reverse<int>().Take(1))
.Skip(1),
(v1, v2) =>
new
{
V = v1,
G = (v2 - v1) != 1 ? index++ : index
})
.GroupBy(x => x.G, x => x.V, (k, l) => l.ToList())
.ToList();
External index is building an index of consecutive groups that have value difference of 1. Then you can simply GroupBy with respect to this index.
To clarify solution, here is how this collection looks without grouping (GroupBy commented):
Assuming your input is in order, the following will work:
var grouped = input.Select((n, i) => new { n, d = n - i }).GroupBy(p => p.d, p => p.n);
It won't work if your input is e.g. { 1, 2, 3, 999, 5, 6, 7 }.
You'd get { { 1, 2, 3, 5, 6, 7 }, { 999 } }.
This works:
var results =
listOfInt
.Skip(1)
.Aggregate(
new List<List<int>>(new [] { listOfInt.Take(1).ToList() }),
(a, x) =>
{
if (a.Last().Last() + 1 == x)
{
a.Last().Add(x);
}
else
{
a.Add(new List<int>(new [] { x }));
}
return a;
});
I get this result:
Consider the following structure:
IEnumerable<IEnumerable<int>> collection = new[] {
new [] {1, 2, 3},
new [] {4, 5, 6},
new [] {7, 8, 9}
};
How can I enumerate this collection so that I obtain IEnumerable<int> collections made up of the first items, second items, etc.?
That is, {1, 4, 7}, {2, 5, 8}, ...
(Though the implementation I've chosen is int[] objects, assume you only have IEnumerable<int> functionality. Thanks.)
Here's an approach that uses a generator instead of recursion. There's less array construction too, so it might be faster, but that's totally conjecture.
public static IEnumerable<IEnumerable<T>> Transpose<T>(
this IEnumerable<IEnumerable<T>> #this)
{
var enumerators = #this.Select(t => t.GetEnumerator())
.Where(e => e.MoveNext());
while (enumerators.Any()) {
yield return enumerators.Select(e => e.Current);
enumerators = enumerators.Where(e => e.MoveNext());
}
}
Just my 2 cents
In pure linq:
var transpond = collection.First().Select((frow,i)=>collection.Select(row=>row.ElementAt(i)));
Or with some inpurity:
var r1 = collection.First().Select((frow, i) => collection.Select(row => row.ToArray()[i]));
Code credit goes here (untested but looks fine).
public static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> values)
{
if (!values.Any())
return values;
if (!values.First().Any())
return Transpose(values.Skip(1));
var x = values.First().First();
var xs = values.First().Skip(1);
var xss = values.Skip(1);
return
new[] {new[] {x}
.Concat(xss.Select(ht => ht.First()))}
.Concat(new[] { xs }
.Concat(xss.Select(ht => ht.Skip(1)))
.Transpose());
}
}
//Input: transpose [[1,2,3],[4,5,6],[7,8,9]]
//Output: [[1,4,7],[2,5,8],[3,6,9]]
var result = new[] {new[] {1, 2, 3}, new[] {4, 5, 6}, new[] {7, 8, 9}}.Transpose();
Assuming all the sequences are of the same length.
static void Main(string[] args)
{
IEnumerable<IEnumerable<int>> collection =
new[]
{
new [] {1, 2, 3},
new [] {4, 5, 6 },
new [] {7, 8, 9}
};
Console.WriteLine("\tInitial");
Print(collection);
var transposed =
Enumerable.Range(0, collection.First().Count())
.Select(i => collection.Select(j => j.ElementAt(i)));
Console.WriteLine("\tTransposed");
Print(transposed);
}
static void Print<T>(IEnumerable<IEnumerable<T>> collection)=>
Console.WriteLine(string.Join(Environment.NewLine, collection.Select(i => string.Join(" ", i))));
Gives:
Initial
1 2 3
4 5 6
7 8 9
Transposed
1 4 7
2 5 8
3 6 9
If all elements are guaranteed to be the same length, you could do this:
IEnumerable<IEnumerable<int>> Transpose(IEnumerable<IEnumerable<int>> collection)
{
var width = collection.First().Count();
var flattened = collection.SelectMany(c => c).ToArray();
var height = flattened.Length / width;
var result = new int[width][];
for (int i = 0; i < width; i++)
{
result[i] = new int[height];
for (int j = i, k = 0; j < flattened.Length; j += width, k++)
result[i][k] = flattened[j];
}
return result;
}