Related
I have an unknown number of buckets(collections), and each bucket having an unknown number of entities
I need to produce a cartesian product of all the entities, so that I endup with a single COLLECTION that has ARRAYS of entities and in each array, there is 1 representetive from EVERY bucket.
So that if I have 5 buckets (B1..B5), and buckets B1, B2 have 1 item each, and bucket B3, B4 and B5 have 4, 8 and 10 items each, I'll have a collection of 320 arrays, and each array will have 5 items.
The only stupud issue here, is that both size of buckets and number of buckets is unknown at development time.
Performance is not super important here, as most of the time, my buckets will have only 1 entity, and only rarely will there be times when some of my buckets will contain 20-30 items...and I'll usually have 5-30 buckets
I'd love to utilize linq here in someway, but my brain is getting fried as I try to imagine how this would work
You could create an extension method like the following:
public static class EnumerableExtensions
{
public static IEnumerable<TValue []> Permutations<TKey, TValue>(this IEnumerable<TKey> keys, Func<TKey, IEnumerable<TValue>> selector)
{
var keyArray = keys.ToArray();
if (keyArray.Length < 1)
yield break;
TValue [] values = new TValue[keyArray.Length];
foreach (var array in Permutations(keyArray, 0, selector, values))
yield return array;
}
static IEnumerable<TValue []> Permutations<TKey, TValue>(TKey [] keys, int index, Func<TKey, IEnumerable<TValue>> selector, TValue [] values)
{
Debug.Assert(keys.Length == values.Length);
var key = keys[index];
foreach (var value in selector(key))
{
values[index] = value;
if (index < keys.Length - 1)
{
foreach (var array in Permutations(keys, index+1, selector, values))
yield return array;
}
else
{
yield return values.ToArray(); // Clone the array;
}
}
}
}
As an example, it could be used like:
public static void TestPermutations()
{
int [][] seqence = new int [][]
{
new int [] {1, 2, 3},
new int [] {101},
new int [] {201},
new int [] {301, 302, 303},
};
foreach (var array in seqence.Permutations(a => a))
{
Debug.WriteLine(array.Aggregate(new StringBuilder(), (sb, i) => { if (sb.Length > 0) sb.Append(","); sb.Append(i); return sb; }));
}
}
and produce the following output:
1,101,201,301
1,101,201,302
1,101,201,303
2,101,201,301
2,101,201,302
2,101,201,303
3,101,201,301
3,101,201,302
3,101,201,303
Is that what you want?
Here's how to do it without recursion in a single Linq statement (wrapped around an extension method for convenience):
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(
IEnumerable<IEnumerable<T>> listOfLists)
{
return listOfLists.Skip(1)
.Aggregate(listOfLists.First()
.Select(c => new List<T>() { c }),
(previous, next) => previous
.SelectMany(p => next.Select(d => new List<T>(p) { d })));
}
The idea is simple:
Skip the first row, so we can use it as the initial value of an aggregate.
Place this initial value in a list that we'll grow on each iteration.
On each iteration, create a new list for each element in previous and add to it each of the elements in next (this is done by new List<T>(p) { d }).
EXAMPLE
Suppose you have an array of arrays as follows:
var arr = new[] {
new[] { 1,2 },
new[] { 10,11,12 },
new[] { 100,101 }
};
Then arr.GetPermutations() will return a list of lists containing:
1,10,100
1,10,101
1,11,100
1,11,101
1,12,100
1,12,101
2,10,100
2,10,101
2,11,100
2,11,101
2,12,100
2,12,101
Non-Linq, non-recursive solution that's faster. We pre-allocate the entire output matrix and then just fill it in a column at a time.
T[][] Permutations<T>(T[][] vals)
{
int numCols = vals.Length;
int numRows = vals.Aggregate(1, (a, b) => a * b.Length);
var results = Enumerable.Range(0, numRows)
.Select(c => new T[numCols])
.ToArray();
int repeatFactor = 1;
for (int c = 0; c < numCols; c++)
{
for (int r = 0; r < numRows; r++)
results[r][c] = vals[c][r / repeatFactor % vals[c].Length];
repeatFactor *= vals[c].Length;
}
return results;
}
Another LINQ-based option, based on suggestion from Diego, but more precise in terms of argument and return types.
It also does not require multiple enumerations of outer collection and hence does not produce Resharper's hint "Possible multiple enumerations".
public static IEnumerable<IReadOnlyCollection<T>> GetPermutations<T>(
IEnumerable<IReadOnlyCollection<T>> collections) =>
collections
.Aggregate(
new[] { Array.Empty<T>() },
(acc, next) =>
acc
.SelectMany(accItem =>
next.Select(nextItem => accItem.Concat(new[] { nextItem }).ToArray()))
.ToArray());
This is probably a very late answer, but I encounter a similar problem i.e. generate all permutations of a list of list of string. However, in my problem, I don't need all permutations simultaneously. I only need/generate next permutation if current permutation doesn't satisfy my condition. Therefore, the following is my way of doing a kind of "for each" and with conditional continuation during permutations generation. This answer is inpsired by Tom19's answer.
void ForEachPermutationDo<T>(IEnumerable<IEnumerable<T>> listOfList, Func<IEnumerable<T>, bool> whatToDo) {
var numCols = listOfList.Count();
var numRows = listOfList.Aggregate(1, (a, b) => a * b.Count());
var continueGenerating = true;
var permutation = new List<T>();
for (var r = 0; r < numRows; r++) {
var repeatFactor = 1;
for (var c = 0; c < numCols; c++) {
var aList = listOfList.ElementAt(c);
permutation.Add(aList.ElementAt((r / repeatFactor) % aList.Count()));
repeatFactor *= aList.Count();
}
continueGenerating = whatToDo(permutation.ToList()); // send duplicate
if (!continueGenerating) break;
permutation.Clear();
}
}
Using the above method, generating all permutation can be done like
IEnumerable<IEnumerable<T>> GenerateAllPermutations<T>(IEnumerable<IEnumerable<T>> listOfList) {
var results = new List<List<T>>();
ForEachPermutationDo(listOfList, (permutation) => {
results.Add(permutation);
return true;
});
return results;
}
I have an unknown number of buckets(collections), and each bucket having an unknown number of entities
I need to produce a cartesian product of all the entities, so that I endup with a single COLLECTION that has ARRAYS of entities and in each array, there is 1 representetive from EVERY bucket.
So that if I have 5 buckets (B1..B5), and buckets B1, B2 have 1 item each, and bucket B3, B4 and B5 have 4, 8 and 10 items each, I'll have a collection of 320 arrays, and each array will have 5 items.
The only stupud issue here, is that both size of buckets and number of buckets is unknown at development time.
Performance is not super important here, as most of the time, my buckets will have only 1 entity, and only rarely will there be times when some of my buckets will contain 20-30 items...and I'll usually have 5-30 buckets
I'd love to utilize linq here in someway, but my brain is getting fried as I try to imagine how this would work
You could create an extension method like the following:
public static class EnumerableExtensions
{
public static IEnumerable<TValue []> Permutations<TKey, TValue>(this IEnumerable<TKey> keys, Func<TKey, IEnumerable<TValue>> selector)
{
var keyArray = keys.ToArray();
if (keyArray.Length < 1)
yield break;
TValue [] values = new TValue[keyArray.Length];
foreach (var array in Permutations(keyArray, 0, selector, values))
yield return array;
}
static IEnumerable<TValue []> Permutations<TKey, TValue>(TKey [] keys, int index, Func<TKey, IEnumerable<TValue>> selector, TValue [] values)
{
Debug.Assert(keys.Length == values.Length);
var key = keys[index];
foreach (var value in selector(key))
{
values[index] = value;
if (index < keys.Length - 1)
{
foreach (var array in Permutations(keys, index+1, selector, values))
yield return array;
}
else
{
yield return values.ToArray(); // Clone the array;
}
}
}
}
As an example, it could be used like:
public static void TestPermutations()
{
int [][] seqence = new int [][]
{
new int [] {1, 2, 3},
new int [] {101},
new int [] {201},
new int [] {301, 302, 303},
};
foreach (var array in seqence.Permutations(a => a))
{
Debug.WriteLine(array.Aggregate(new StringBuilder(), (sb, i) => { if (sb.Length > 0) sb.Append(","); sb.Append(i); return sb; }));
}
}
and produce the following output:
1,101,201,301
1,101,201,302
1,101,201,303
2,101,201,301
2,101,201,302
2,101,201,303
3,101,201,301
3,101,201,302
3,101,201,303
Is that what you want?
Here's how to do it without recursion in a single Linq statement (wrapped around an extension method for convenience):
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(
IEnumerable<IEnumerable<T>> listOfLists)
{
return listOfLists.Skip(1)
.Aggregate(listOfLists.First()
.Select(c => new List<T>() { c }),
(previous, next) => previous
.SelectMany(p => next.Select(d => new List<T>(p) { d })));
}
The idea is simple:
Skip the first row, so we can use it as the initial value of an aggregate.
Place this initial value in a list that we'll grow on each iteration.
On each iteration, create a new list for each element in previous and add to it each of the elements in next (this is done by new List<T>(p) { d }).
EXAMPLE
Suppose you have an array of arrays as follows:
var arr = new[] {
new[] { 1,2 },
new[] { 10,11,12 },
new[] { 100,101 }
};
Then arr.GetPermutations() will return a list of lists containing:
1,10,100
1,10,101
1,11,100
1,11,101
1,12,100
1,12,101
2,10,100
2,10,101
2,11,100
2,11,101
2,12,100
2,12,101
Non-Linq, non-recursive solution that's faster. We pre-allocate the entire output matrix and then just fill it in a column at a time.
T[][] Permutations<T>(T[][] vals)
{
int numCols = vals.Length;
int numRows = vals.Aggregate(1, (a, b) => a * b.Length);
var results = Enumerable.Range(0, numRows)
.Select(c => new T[numCols])
.ToArray();
int repeatFactor = 1;
for (int c = 0; c < numCols; c++)
{
for (int r = 0; r < numRows; r++)
results[r][c] = vals[c][r / repeatFactor % vals[c].Length];
repeatFactor *= vals[c].Length;
}
return results;
}
Another LINQ-based option, based on suggestion from Diego, but more precise in terms of argument and return types.
It also does not require multiple enumerations of outer collection and hence does not produce Resharper's hint "Possible multiple enumerations".
public static IEnumerable<IReadOnlyCollection<T>> GetPermutations<T>(
IEnumerable<IReadOnlyCollection<T>> collections) =>
collections
.Aggregate(
new[] { Array.Empty<T>() },
(acc, next) =>
acc
.SelectMany(accItem =>
next.Select(nextItem => accItem.Concat(new[] { nextItem }).ToArray()))
.ToArray());
This is probably a very late answer, but I encounter a similar problem i.e. generate all permutations of a list of list of string. However, in my problem, I don't need all permutations simultaneously. I only need/generate next permutation if current permutation doesn't satisfy my condition. Therefore, the following is my way of doing a kind of "for each" and with conditional continuation during permutations generation. This answer is inpsired by Tom19's answer.
void ForEachPermutationDo<T>(IEnumerable<IEnumerable<T>> listOfList, Func<IEnumerable<T>, bool> whatToDo) {
var numCols = listOfList.Count();
var numRows = listOfList.Aggregate(1, (a, b) => a * b.Count());
var continueGenerating = true;
var permutation = new List<T>();
for (var r = 0; r < numRows; r++) {
var repeatFactor = 1;
for (var c = 0; c < numCols; c++) {
var aList = listOfList.ElementAt(c);
permutation.Add(aList.ElementAt((r / repeatFactor) % aList.Count()));
repeatFactor *= aList.Count();
}
continueGenerating = whatToDo(permutation.ToList()); // send duplicate
if (!continueGenerating) break;
permutation.Clear();
}
}
Using the above method, generating all permutation can be done like
IEnumerable<IEnumerable<T>> GenerateAllPermutations<T>(IEnumerable<IEnumerable<T>> listOfList) {
var results = new List<List<T>>();
ForEachPermutationDo(listOfList, (permutation) => {
results.Add(permutation);
return true;
});
return results;
}
When i have a list
IList<int> list = new List<int>();
list.Add(100);
list.Add(200);
list.Add(300);
list.Add(400);
list.Add(500);
What is the way to extract a pairs
Example : List elements {100,200,300,400,500}
Expected Pair : { {100,200} ,{200,300} ,{300,400} ,{400,500} }
The most elegant way with LINQ: list.Zip(list.Skip(1), Tuple.Create)
A real-life example: This extension method takes a collection of points (Vector2) and produces a collection of lines (PathSegment) needed to 'join the dots'.
static IEnumerable<PathSegment> JoinTheDots(this IEnumerable<Vector2> dots)
{
var segments = dots.Zip(dots.Skip(1), (a,b) => new PathSegment(a, b));
return segments;
}
This will give you an array of anonymous "pair" objects with A and B properties corresponding to the pair elements.
var pairs = list.Where( (e,i) => i < list.Count - 1 )
.Select( (e,i) => new { A = e, B = list[i+1] } );
You can use a for loop:
var pairs = new List<int[]>();
for(int i = 0; i < list.Length - 1; i++)
pairs.Add(new [] {list[i], list[i + 1]);
You can also use LINQ, but it's uglier:
var pairs = list.Take(list.Count - 1).Select((n, i) => new [] { n, list[i + 1] });
EDIT: You can even do it on a raw IEnumerable, but it's much uglier:
var count = list.Count();
var pairs = list
.SelectMany((n, i) => new [] { new { Index = i - 1, Value = n }, new { Index = i, Value = n } })
.Where(ivp => ivp.Index >= 0 && ivp.Index < count - 1) //We only want one copy of the first and last value
.GroupBy(ivp => ivp.Index, (i, ivps) => ivps.Select(ivp => ivp.Value));
More general would be:
public static IEnumerable<TResult> Pairwise<TSource, TResult>(this IEnumerable<TSource> values, int count, Func<TSource[], TResult> pairCreator)
{
if (count < 1) throw new ArgumentOutOfRangeException("count");
if (values == null) throw new ArgumentNullException("values");
if (pairCreator == null) throw new ArgumentNullException("pairCreator");
int c = 0;
var data = new TSource[count];
foreach (var item in values)
{
if (c < count)
data[c++] = item;
if (c == count)
{
yield return pairCreator(data);
c = 0;
}
}
}
Following solution uses zip method. Zip originalList and originalList.Skip(1) so that one gets desired result.
var adjacents =
originalList.Zip(originalList.Skip(1),
(a,b) => new {N1 = a, N2 = b});
Using .Windowed() from MoreLINQ:
var source = new[] {100,200,300,400,500};
var result = source.Windowed(2).Select(x => Tuple.Create(x.First(),x.Last()));
Off the top of my head and completely untested:
public static T Pairwise<T>(this IEnumerable<T> list)
{
T last;
bool firstTime = true;
foreach(var item in list)
{
if(!firstTime)
return(Tuple.New(last, item));
else
firstTime = false;
last = item;
}
}
I have a datatable and I am doing operations on it to take the result like this:
var result = from row in DTgraph.AsEnumerable()
group row by row.Field<string>("Campaign") into grp
select new
{
Campaign = grp.Key,
Count = grp.Count(),
SL = grp.Sum(s => s.Field<Decimal>("Inb.ServiceLevel"))
};
I want to loop on that result
I tried these two ways:
First
for (int i=0;i< result.Count(); i++){
{
}
but I couldn't type result[i].Count
second
foreach (var item in result)
{
}
Your LINQ expression returns an IEnumerable, which cannot be accessed through an indexer. This is why result[i] in your first attempt does not work.
The fix is simple: Convert your IEnumerable to a List:
var result = (from ... select new { ... }).ToList();
var result = (from row in DTgraph.AsEnumerable()
group row by row.Field<string>("Campaign") into grp
select new
{
Campaign = grp.Key,
Count = grp.Count(),
SL = grp.Sum(s => s.Field<Decimal>("Inb.ServiceLevel"))
}).ToList();
if(result.Count() > 0)
{
///Do Something////
}
Why do you need that? Use for instead.
Anyway, if you insist, you can create an extension function that will provide this functionallity. Something like this:
public static void ForEachIndex<T>(this IEnumerable<T> collection, Action<T, int> action)
{
int index = 0;
foreach (T curr in collection)
{
action(curr, index);
index++;
}
}
Usage:
List<int> collection = new List<int> {1,2,3,4,5};
int output = 0;
collection.ForEachIndex((curr,idx) => output += curr * idx);
int x = 9;
List<string> list = new List<string> {"a", "b"};
I want list to be: a b a b a ... until list.Count = x. How might I achieve this?
You could do it with LINQ easily:
List<string> result = (from ignored in Enumerable.Range(0, int.MaxValue)
from item in list
select item).Take(count).ToList();
Or without using a query expression:
List<string> result = Enumerable.Range(0, int.MaxValue)
.SelectMany(ignored => list)
.Take(count)
.ToList();
The use of Enumerable.Range here is just to force repetition - like Ani's approach of using Enumerable.Repeat, which will work too of course.
How about:
var result= Enumerable.Repeat(new[] { "a", "b" }, int.MaxValue)
.SelectMany(strArray => strArray)
.Take(x)
.ToList();
Something like this should work. I did not check it, let it be an exercise for you :)
int currentCount = list.Count;
for (int i=0; i<x; ++i)
{
list.Add(list[i%currentCount]);
}
int x = 9;
List<string> list = new List<string> {};
for (int i = 0; i < x; i++)
{
list.Add("a");
list.Add("b");
}
// verify
foreach (var item in list)
{
Console.WriteLine(item);
}