List<int> ints = new List<int>();
ints.Add(1,5,6);
How to get 5 and 6 in a new list?
I tried this but it didn't work
List<int> newList = new List<int>();
newList = ints.Select((i, j) => i - j).Skip(1).ToList();
Thanks and please don't judge too harshly, not an expert.
CodePudding user response:
I suggest to split your problem into two easier problems:
Find all the indices where a new sequence of consecutive numbers starts. To do that, loop through the list and remember (= put into a new list) all indices where the number is not equal to the previous number 1.
Split your list on these indices. To do that, loop through the list of indices you created in step 1 and create new lists based on those indices.
CodePudding user response:
I suspect this is where you were going with your LINQ:
An array of sorted, unique numbers, formatted so it's more obvious which the consecutives are
var ints = new[] {
1, 2, 3,
5, 6,
8, 9, 10, 11,
15, 16, 17,
20, 21, 22,
25,
27,
30, 31
};
And a LINQ that collects consecutives:
var consecs = ints
.Select((item, idx) => new { I = item, G = item - idx })
.GroupBy(
ig => ig.G,
ig => ig.I,
(k, g) => g.ToArray()
)
.Where(a => a.Length > 1)
.ToArray();
How does it work?
- The Select produces a new object that numbers the ints in the array, from 0 i.e. you get the number itself in
item, and the index it's at inidx. We subtract the idex from the number. Because indexes increment by one each time, any run of numbers that also increments by one each time will produce a fixed value for G:item == 1, idx == 0, G == 1,item == 2, idx == 1, G == 1,item == 3, idx == 2, G == 1,item == 5, idx == 3, G == 2,item == 6, idx == 4, G == 2,- and so on
- The group has 3 parameters:
- what to group by:
ig => ig.G- groups by G, which makes LINQ collect all items in the same G into a list. The input parameter is calledigbecause it's an anonymous type of I and G - what to put in the list-of-I-with-same-G:
ig => ig.I- just theIitem, meaning the output will be a list of ints, i.e. the original items - what to do to the output list:
(k, g) => g.ToArray()- turn it from a grouping into an array.kis the grouping key (formerly called G); we don't need it.gis the list of numbers groupby collected wothether with the same G. It's normally a Grouping but we can transform it to anint[]at this stage
- what to group by:
- Then we run a
Whereto exclude arrays of only one item, because they aren't a consecutive run of two or more numbers. The group by output anEnumerable<int[]>soais anint[] - ToArray at the end just turns the enumerable of arrays, that Where filtered for us, into an array of arrays, so the output is an
int[][]
This means you end up with groups like:
consecs[0] -> new [] { 1,2,3 };
consecs[1] -> new [] { 5,6 };
consecs[2] -> new [] { 5,6 };
--
So you want to do it without LINQ?
OK, let's use a Dictionary<int,List<int>> to collect items under the same group number. We'll calculate the key of the dictionary from item-index like before, and we'll make sure it exists as a new list, and then we'll add items to it. Then we'll skip over any lists that are only 1 big
var ints = new[] {
1, 2, 3,
5, 6,
8, 9, 10, 11,
15, 16, 17,
20, 21, 22,
25,
27,
30, 31
};
var d = new Dictionary<int, List<int>>();
for(int idx = 0; idx < ints.Length; idx ){
var g = ints[idx] - idx;
d.TryAdd(g, new List<int>()); //make sure a list exists for g; does nothing if g is known
d[g].Add(ints[idx]);
}
foreach(var kvp in d){
if(kvp.Value.Count == 1)
continue; //skip lists of only one item
//do whatever with your list of consecutive ints
}
