I was writing a PascalCaseParser using Regex.Split
and I came to the desire to select two items from an collection at a time.
This example code demonstrates.
void Main()
{
string pascalCasedString = "JustLikeYouAndMe";
var words = WordsFromPascalCasedString(pascalCasedString);
words.Dump();
}
IEnumerable<string> WordsFromPascalCasedString(string pascalCasedString)
{
var rx = new Regex("([A-Z])");
return rx.Split(pascalCasedString)
.Where(c => !string.IsNullOrEmpty(c))
// how to select 2 elements at a time?
;
}
The result of above code is:
IEnumerable<String> (10 items)
J
ust
L
ike
Y
ou
A
nd
M
e
Every two elements of the collection make one result that I want the function WordsFromPascalCasedString
to yield.
My questions is: How would you, in general, deal with a requirement to return two items at a time. I'm curious if there are any interesting non-brute-force approaches.
Personally, I'd go with Simon Belanger's answer in this particular case. But in general, to select consecutive pairs, from an IEnumerable
, you'd use this:
IEnumerable<Tuple<string, string>> WordsFromPascalCasedString(string pascalCasedString)
{
var rx = new Regex("([A-Z])");
var array = rx.Split(pascalCasedString)
.Where(c => !string.IsNullOrEmpty(c))
.ToArray();
var items = Enumerable.Range(0, array.Length / 2)
.Select(i => Tuple.Create(array[i * 2], array[i * 2 + 1]);
}
Or this, which takes more effort, but it's reusable and more efficient:
IEnumerable<Tuple<T, T>> Pairs<T>(IEnumerable<T> input)
{
var array = new T[2];
int i = 0;
foreach(var x in input)
{
array[i] = x;
i = (i + 1) % 2;
if (i == 0)
{
yield return Tuple.Create(array[0], array[1]);
}
}
}
IEnumerable<Tuple<string, string>> WordsFromPascalCasedString(string pascalCasedString)
{
var rx = new Regex("([A-Z])");
var output = rx.Split(pascalCasedString)
.Where(c => !string.IsNullOrEmpty(c));
var items = Pairs(output);
}
It can easily be extended to groups of n
:
IEnumerable<IEnumerable<T>> Batches<T>(IEnumerable<T> input, int n)
{
var array = new T[n];
int i = 0;
foreach(var x in input)
{
array[i] = x;
i = (i + 1) % n;
if (i == 0)
{
yield return array.ToArray();
}
}
if (i != 0)
{
yield return array.Take(i);
}
}
A similar method exists in MoreLINQ
.
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