How to Split an Ienumerable<String> into Groups of Ienumerable<String>

How can I split an IEnumerableString into groups of IEnumerablestring

var result = sequence.Select((s, i) => new { Value = s, Index = i })
.GroupBy(item => item.Index / 3, item => item.Value);

Note that this will return an IEnumerable<IGrouping<int,string>> which will be functionally similar to what you want. However, if you strictly need to type it as IEnumerable<IEnumerable<string>> (to pass to a method that expects it in C# 3.0 which doesn't support generics variance,) you should use Enumerable.Cast:

var result = sequence.Select((s, i) => new { Value = s, Index = i })
.GroupBy(item => item.Index / 3, item => item.Value)
.Cast<IEnumerable<string>>();

Split an IEnumerable into multiple IEnumerables

Try this:

public static IEnumerable<IList<Couple>> Split(IEnumerable<Couple> couples)
{
using (var enumerator = couples.GetEnumerator())
{
if (!enumerator.MoveNext())
{
yield break;
}
var current = enumerator.Current;
var group = new List<Couple> { current };
while (enumerator.MoveNext())
{
var next = enumerator.Current;
if (current.Indicator.Equals(next.Indicator))
{
group.Add(next);
}
else
{
yield return group;
group = new List<Couple> { next };
}
current = next;
}
yield return group;
}
}

Example:

var couples = new List<Couple> 
{
new Couple("a",false),
new Couple("b",false),
new Couple("c",true),
new Couple("d",false),
new Couple("e",false),
new Couple("f",true),
new Couple("g",true),
new Couple("h",true),
new Couple("i",false),
new Couple("j",true),
new Couple("k",true),
new Couple("l",false),
new Couple("m",false),
};

var groupNr = 1;
foreach (var couplesGroup in Split(couples))
{
Console.WriteLine($"List {groupNr++}: ");
foreach (var couple in couplesGroup)
{
Console.WriteLine($"{couple.Text, 10}, {couple.Indicator}");
}
Console.WriteLine();
}

How to split IEnumerablestring to groups by separator?

Try the algorithm below. This will add a group of words to the dictionary whenever it comes across an empty line.

List<string> input = new List<string>()
{
"1",
"wordOfGroup11",
"wordOfGroup12",
"wordOfGroup1N",
"\n",
"2",
"wordOfGroup21",
"wordOfGroup22",
"\n"
};

Dictionary<string, List<string>> result = new Dictionary<string, List<string>>();
string firstWordOfGroup = "";
List<string> allWordsInGroup = new List<string>();

foreach (string line in input)
{
if (int.TryParse(line, out int index) == true)
{
allWordsInGroup.Clear();
continue;
}
// I don't know what "EmptyLine" means
if (line == "\n" || line == Environment.NewLine || line == string.Empty)
{
result.Add(firstWordOfGroup, allWordsInGroup);
}
else
{
if (allWordsInGroup.Count == 0)
{
firstWordOfGroup = line;
}

allWordsInGroup.Add(line);
}
}

Also note that if your groups can have the same first word (e.g. both starting with "WordOfGroup1" then you should use a List<KeyValuePair<string, List<string>>> because the dictionary does not store duplicate keys.

Split an IEnumerableT into fixed-sized chunks (return an IEnumerableIEnumerableT where the inner sequences are of fixed length)

You could try to implement Batch method mentioned above on your own like this:

    static class MyLinqExtensions 
{
public static IEnumerable<IEnumerable<T>> Batch<T>(
this IEnumerable<T> source, int batchSize)
{
using (var enumerator = source.GetEnumerator())
while (enumerator.MoveNext())
yield return YieldBatchElements(enumerator, batchSize - 1);
}

private static IEnumerable<T> YieldBatchElements<T>(
IEnumerator<T> source, int batchSize)
{
yield return source.Current;
for (int i = 0; i < batchSize && source.MoveNext(); i++)
yield return source.Current;
}
}

I've grabbed this code from http://blogs.msdn.com/b/pfxteam/archive/2012/11/16/plinq-and-int32-maxvalue.aspx.

UPDATE: Please note, that this implementation not only lazily evaluates batches but also items inside batches, which means it will only produce correct results when batch is enumerated only after all previous batches were enumerated. For example:

public static void Main(string[] args)
{
var xs = Enumerable.Range(1, 20);
Print(xs.Batch(5).Skip(1)); // should skip first batch with 5 elements
}

public static void Print<T>(IEnumerable<IEnumerable<T>> batches)
{
foreach (var batch in batches)
{
Console.WriteLine($"[{string.Join(", ", batch)}]");
}
}

will output:

[2, 3, 4, 5, 6] //only first element is skipped.
[7, 8, 9, 10, 11]
[12, 13, 14, 15, 16]
[17, 18, 19, 20]

So, if you use case assumes batching when batches are sequentially evaluated, then lazy solution above will work, otherwise if you can't guarantee strictly sequential batch processing (e.g. when you want to process batches in parallel), you will probably need a solution which eagerly enumerates batch content, similar to one mentioned in the question above or in the MoreLINQ

Splitting an IEnumerable into two

Here is one simple method. Note that ToLookup eagerly evaluates the input sequence.

List<int> list = new List<int> { 1, 2, 3, 4, 5, 6 };

var lookup = list.ToLookup(num => num % 2 == 0);

IEnumerable<int> trueList = lookup[true];
IEnumerable<int> falseList = lookup[false];

You can use GroupBy to get lazy evaluation of the input sequence, but it's not quite as pretty:

var groups = list.GroupBy(num => num % 2 == 0);

IEnumerable<int> trueList = groups.Where(group => group.Key).FirstOrDefault();
IEnumerable<int> falseList = groups.Where(group => !group.Key).FirstOrDefault();

Group IEnumerable into a string

Linq has a nice group by statement:

var emailGroup = emailList.GroupBy(e => e.alertCategory);

Then you can loop through each grouping and do whatever you want:

foreach(var grouping in emailGroup)
{
//do whatever you want here.
//note grouping will access the list of grouped items, grouping.Key will show the grouped by field
}

Edit:

To retrieve a group after you have grouped them, just use Where for more than one or First for just one:

var group = emailGroup.First(g => g.Key == "name you are looking for");

or

var groups = emailGroup.Where(g => listOfWantedKeys.Contains(g.Key));

this is a lot more efficient than looping through every time you need to find something.

Split a string into groups

Consider the following code...

        string message = "0123456789";//10char string
//string message = "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";//161char string
int parts = (message.Length/ 153) + (message.Length % 153 > 0 ? 1 : 0);
for (int x = 1; x <= parts; x++)
{
Console.WriteLine("this Msg Part: " + x.ToString());
Console.WriteLine("this Msg Part Text:" + message.Substring( (x-1)* 153, message.Length < ((x-1)* 153 + 153) ? message.Length - (x-1)* 153 : 153));
Console.WriteLine("Total Msg Parts: " + parts.ToString());
}

Good Luck!

Divide a large IEnumerable into smaller IEnumerable of a fix amount of item

Try something like this:

var result = items.Select((value, index) => new { Index = index, Value = value})
.GroupBy(x => x.Index / 5)
.Select(g => g.Select(x => x.Value).ToList())
.ToList();

It works by partitioning the items into groups based on their index in the original list.

C# LINQ split complex joined string data to a List of objects

Normal enumerable.Zip

var result = someObject_source.Model.Split(Delimeter_main)
.Zip(someObject_source.Color.Split(Delimeter_main), (x, y) => new { x, y })
.Zip(someObject_source.Size.Split(Delimeter_main), (zip1, z) =>
{
var secondSplit = z.Split(Delimeter_inner);
return new SomeObject_target
{
Model = zip1.x,
Color = zip1.y,
Size = secondSplit[0],
Quantity = double.TryParse(secondSplit[1], out double _quantity) ? _quantity : 1,
Nett = double.TryParse(secondSplit[2], out double _nett) ? _nett : 1,
};
});

Extention Method Zip on 3 collection

A little more readable, without the annonymous object wraper for the first Zip result.

var results = someObject_source.Model.Split(Delimeter_main)
.ZipThree(
someObject_source.Color.Split(Delimeter_main),
someObject_source.Size.Split(Delimeter_main),
(x, y, z) => {
var secondSplit = z.Split(Delimeter_inner);
return new SomeObject_target
{
Model = x,
Color = y,
Size = secondSplit[0],
Quantity = double.TryParse(secondSplit[1], out double _quantity) ? _quantity : 1,
Nett = double.TryParse(secondSplit[2], out double _nett) ? _nett : 1,
};
}
);


Related Topics



Leave a reply



Submit