Is there a way to break a string into pairs without looking at indexes? e.g. TVBMCVTVFGTVTB would be broken into a list of strings as such:
[TV,BM,CV,TV,FG,TV,TB]
<Convert the string into a char array and then iterate along that making new strings out of pairs of characters.
If you like some esoteric solutions:
1)
string s = "TVBMCVTVFGTVTB";
var splitted = Enumerable.Range(0, s.Length)
.GroupBy(x => x / 2)
.Select(x => new string(x.Select(y => s[y]).ToArray()))
.ToList();
2)
string s = "ABCDEFGHIJKLMN";
var splitted = Enumerable.Range(0, (s.Length + 1) / 2)
.Select(i =>
s[i * 2] +
((i * 2 + 1 < s.Length) ?
s[i * 2 + 1].ToString() :
string.Empty))
.ToList();
If you REALLY want to avoid using indexes...
You could use a Regex "\w\w" or "\w{2,2}" or some variation like that and MSDN - Regex.Matches method to get a MatchCollection which would contain the matches as pairs of characters. Change \w in the regex pattern to suit your needs.
List<string> result = new List<string>();
while (original.Length > 0)
{
result.Add(new String(original.Take(2).ToArray()));
original = new String(original.Skip(2).ToArray());
}
return result;
The LINQ probably uses indices somewhere internally, but I didn't touch any of them so I consider this valid. It works for odd-length originals, too.
Thanks Heinzi for the correction. Demo: http://rextester.com/MWCKYD83206
var s = "TVBMCVTVFGTVTB";
var pairs = Enumerable.Range(0, s.Length / 2)
.Select(i => String.Concat(s.Skip(i * 2).Take(2)));
This will work if you know that s
always is of even length, or you don't accept, or don't care about, ending with singletons for strings with odd length.
If you want to include singleton remainders, for odd length strings, you can simply use ceiling:
var s = "TVBMCVTVFGTVTB";
var pairs = Enumerable.Range(0, (int)Math.Ceiling(s.Length / 2D))
.Select(i => String.Concat(s.Skip(i * 2).Take(2)));
Oh come on, just use indexes like this:
public static class StringExtensions {
public static IEnumerable<string> TakeEvery(this string s, int count) {
int index = 0;
while(index < s.Length) {
if(s.Length - index >= count) {
yield return s.Substring(index, count);
}
else {
yield return s.Substring(index, s.Length - index);
}
index += count;
}
}
}
I have added no guard clauses.
Usage:
var items = "TVBMCVTVFGTVTB".TakeEvery(2);
foreach(var item in items) {
Console.WriteLine(item);
}