Reputation: 43
How can i generate numbers using LinQ in this sequence given the startIndex,count of numbers and the maximum number.For example:
Sample Numbers = 1,2,3,4
StartIndex = 1 (i.e it should start from 1)
Sequence number count = 3
Maximum number = 4 (i.e till 4)
Expected result given the above details :
1,2,3
1,3,4
1,2,4
Is there a way to do it using linQ?
Upvotes: 1
Views: 2439
Reputation: 241641
Okay, first let's state the problem clearly. I'll assume your numbers are int
but that's a mostly irrelevant detail but the concreteness makes thinking go more smo
You have a sequence a_0, a_1, a_2, ..., a_N
of int
.
You have an integer k
satisfying 1 <= k <= N + 1
.
You have a starting index start >=0
and an ending index end <= N
.
You want all subsequences a_i0, a_i1, a_i2, ..., a_ik
of length k
such that i0 = start
and ik = end
.
Then your algorithm is simple. You want to produce all combinations of size k - 2
of { start + 1, ..., end - 1 }
. Given such a combination j1, j2, ..., j(k-1)
, order it, call the resulting ordered sequence i1, i2, ..., i(k-1)
and return the sequence a_start, a_i1, a_i2, ..., a_i(k-1), a_end
.
Now that you know a formal statement of the problem, and what you need to solve it, resources abound for generating said combinations. cf. Google search : Generating combinations C# or Knuth Volume 4A.
Upvotes: 0
Reputation: 10579
If you didn't need the length of you sequences to be dynamic, then you could use:
var startindex=1;
var maxindex=4;
var data = Enumerable.Range(startindex,maxindex);
var qry = from x in data
where x == startindex
from y in data
where x < y
from z in data
where y < z
select new { x, y, z };
foreach (var tuple in qry) {
Console.WriteLine("{0} {1} {2}", tuple.x, tuple.y, tuple.z);
}
The sequence length is hardcoded to 3, because there are 3 enumerables being joined: x, y, z.
If you want to dynamically join an arbitrary number of enumerables, then you can use Eric Lippert's Cartesian Product Linq example.
You pass a set of k sequences of N items, and it will return a set of all combinations of length k.
Now, you don't want repeated elements in your results. So, I added the following to Eric's example:
where accseq.All(accitem => accitem < item)
Here's the final solution (edited for clarity):
var startindex=1;
var maxindex=7;
var count = 3;
// Make a set of count-1 sequences, whose values range from startindex+1 to maxindex
List<List<int>> sequences = new List<List<int>>();
// We only want permutations starting with startindex. So, the first input sequence to be joined should only have the value startindex.
List<int> list1 = new List<int>();
list1.Add(startindex);
sequences.Add(list1);
// The rest of the input sequences to be joined should contain the range startindex+1 .. maxindex
for (int i=1; i< count; i++)
{
sequences.Add(Enumerable.Range(startindex+1,maxindex-startindex).ToList());
}
// Generate the permutations of the input sequences
IEnumerable<IEnumerable<int>> emptyProduct = new[] { Enumerable.Empty<int>() };
var result = sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
where accseq.All(accitem => accitem < item)
select accseq.Concat(new[] {item}));
// Show the result
foreach (var x in result)
{
Console.WriteLine(x);
}
Upvotes: 2
Reputation: 10623
Try this function.
public static IEnumerable<IEnumerable<T>> Permute<T>(IEnumerable<T> list)
{
if (list.Count() == 1)
return new List<IEnumerable<T>> { list };
return list.Select((a, i1) => Permute(list.Where((b, i2) => i2 != i1)).Select(b => (new List<T> { a }).Union(b)))
.SelectMany(c => c);
}
//Here Range(startindex, count)
List<int> list1 = Enumerable.Range(1, 3).ToList();
//generates all permutations
var permutationlist = Permute(list1);
Upvotes: 0