I have an array of elements where the element has a Flagged boolean value.
1 flagged
2 not flagged
3 not flagged
4 flagged
5 not flagged
6 not flagged
7 not flagged
8 flagged
9 not flagged
I want to break it into arrays based on the flagged indicator
output >
array 1 {1,2,3}
array 2 {4,5,6,7}
array 3 {8,9}
Linq doesn't have an operator for this, but I've written an extension method that you may be able to use (in the process of submitting it to MoreLinq, which you should also check out):
Using the operator below, you would write:
var result =
items.Segment( (item,prevItem,idx) => item.Flagged )
.Select( seq => seq.ToArray() ) // converts each sequence to an array
.ToList();
Here's the code of the extension method:
public static IEnumerable<IEnumerable<T>> Segment<T>(IEnumerable<T> sequence, Func<T, T, int, bool> newSegmentIdentifier)
{
var index = -1;
using (var iter = sequence.GetEnumerator())
{
var segment = new List<T>();
var prevItem = default(T);
// ensure that the first item is always part
// of the first segment. This is an intentional
// behavior. Segmentation always begins with
// the second element in the sequence.
if (iter.MoveNext())
{
++index;
segment.Add(iter.Current);
prevItem = iter.Current;
}
while (iter.MoveNext())
{
++index;
// check if the item represents the start of a new segment
var isNewSegment = newSegmentIdentifier(iter.Current, prevItem, index);
prevItem = iter.Current;
if (!isNewSegment)
{
// if not a new segment, append and continue
segment.Add(iter.Current);
continue;
}
yield return segment; // yield the completed segment
// start a new segment...
segment = new List<T> { iter.Current };
}
// handle the case of the sequence ending before new segment is detected
if (segment.Count > 0)
yield return segment;
}
}
I had a similar problem with this, and solved it using GroupBy
and closure.
//sample data
var arrayOfElements = new[] {
new { Id = 1, Flagged = true },
new { Id = 2, Flagged = false },
new { Id = 3, Flagged = false },
new { Id = 4, Flagged = true },
new { Id = 5, Flagged = false },
new { Id = 6, Flagged = false },
new { Id = 7, Flagged = false },
new { Id = 8, Flagged = true },
new { Id = 9, Flagged = false }
};
//this is the closure which will increase each time I see a flagged
int flagCounter = 0;
var query =
arrayOfElements.GroupBy(e =>
{
if (e.Flagged)
flagCounter++;
return flagCounter;
});
What it does is grouping on an int (flagCounter
), which is increased each time a Flagged element is found.
Please note this won't work with AsParallel()
.
Testing the results:
foreach(var group in query)
{
Console.Write("\r\nGroup: ");
foreach (var element in group)
Console.Write(element.Id);
}
Outputs:
Group: 123
Group: 4567
Group: 89
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