views:

3165

answers:

8

E.g. Input string str = "1111222233334444";

return value ArrayList A where A[0] = "1111", A[1] = "2222", etc.

Use of Linq or reg ex would be good.

+13  A: 

Why not loops? Here's something that would do it quite well:

        string str = "111122223333444455";
        int chunkSize = 4;
        int stringLength = str.Length;
        for (int i = 0; i < stringLength ; i += chunkSize)
        {
            if (i + chunkSize > stringLength) chunkSize = stringLength  - i;
            Console.WriteLine(str.Substring(i, chunkSize));

        }
        Console.ReadLine();

I don't know how you'd deal with case where the string is not factor of 4, but not saying you're idea is not possible, just wondering the motivation for it if a simple for loop does it very well? Obviously the above could be cleaned and even put in as an extension method.

Or as mentioned in comments, you know it's /4 then

str = "1111222233334444";
for (int i = 0; i < stringLength; i += chunkSize) 
  {Console.WriteLine(str.Substring(i, chunkSize));}
dove
+1 - Nicely done :)
Andrew Hare
You can pull `int chunkSize = 4` outside of the loop. It will only be modified on the final pass.
John Feminella
@John, edited for that and added in the fives
dove
+1 for a simple and effective solution - this is how I would have done it, although I would've used `i += chunkSize` instead.
Ian Kemp
@ian spot on ;)
dove
Probably a minor quibble, but you should probably also pull the `str.Length` out of the loop and into a local variable. The C# optimizer *may* be able to inline array length, but I think the code as written will do a method call on every loop, which is not efficient, since the size of `str` never changes.
Daniel Pryden
@Daniel, put your idea in there. though I'm not sure that this wouldn't be calculated at runtime, but that's another question ;)
dove
@Daniel coming back to this, pretty sure the that this optimisation would be extracted by the compiler.
dove
+12  A: 
    static IEnumerable<string> Split(string str, int chunkSize)
    {
        return Enumerable.Range(0, str.Length / chunkSize).Select(i => str.Substring(i * chunkSize, chunkSize));
    }
Konstantin Spirin
@Konstantin much more elegant but will it deal with case of string not being a factor of 4? e.g. string str = "111122223333444455";
dove
Will check to see which solution performs best. Konstantin's is easy to follow though IMO.
@dove: red_Amazon in comments to his question said that str.Length % 4 == 0
Konstantin Spirin
@Konstantin ah, didn't see that comment. could make my for loop a one-liner.
dove
+2  A: 

It's not pretty and it's not fast, but it works, it's a one-liner and it's LINQy:

List<string> a = text.ToCharArray().Select((c, i) => new { Char = c, Index = i }).GroupBy(o => o.Index / 4).Select(g => new String(g.Select(o => o.Char).ToArray())).ToList();
Guffa
I love this kind of stuff, +1!
Blindy
@Guffa, nice. probably wouldn't use it but looks good.
dove
One helluva line tho :)
johnc
Is it guaranteed that GroupBy preserves order of elements?
Konstantin Spirin
@Konstantin: Yes.
Guffa
+8  A: 

Using regular expressions and Linq:

List<string> groups = (from Match m in Regex.Matches(str, @"\d{4}")
                       select m.Value).ToList();

I find this to be more readable, but it's just a personal opinion. It can also be a one-liner : ).

JG
Change the pattern to @"\d{1,4}" and it works for any string length. :)
Guffa
+1 Though this is slower than the other solutions, it's definitely very readable. It's not clear to me whether the OP requires digits or arbitrary characters; it'd probably be wise to replace the `\d` character class with a `.` and to specify `RegexOptions.Singleline`.
Eamon Nerbonne
+5  A: 

In a combination of dove+Konstatin's answers...

static IEnumerable<string> Chunk(string str, int chunkSize) {
    for (int i = 0; i < str.Length; i += chunkSize) 
        yield return str.Substring(i, chunkSize);
}

Or, if you want to support strings that aren't a whole number of chunks...

static IEnumerable<string> Chunk(string str, int chunkSize) {
    for (int i = 0; i < str.Length; i += chunkSize) 
        yield return str.Substring(i, Math.Min(chunkSize, str.Length-i));
}
Eamon Nerbonne
+1 worth a nod. kinda hits nail upon head. he's looking for succinct sytnax and you're also giving the (probably) better performance.
dove
And if you make it "static ... Chunk(this string str, int chunkSize) {" you even have one more "new" C#-Feature into it. Then you can write "1111222233334444".Chunk(4).
MartinStettner
@MartinStettner: That's certainly a decent idea if this is a common operation.
Eamon Nerbonne
+2  A: 

How's this for a one-liner?

List<string> result = new List<string>(Regex.Split(target, @"(?<=\G.{4})"));

With this regex it doesn't matter if the last chunk is less than four characters, because it only ever looks at the characters behind it. I'm sure this isn't the most efficient solution, but I just had to toss it out there. :D

Alan Moore
A: 

How is it done if I want all possible combinations instead of chunks of only 4. For example, if I am given an string which is 1111 (no less than length 4) or 255255255255(no more than length 12).

I want to split up these numbers in every possible combination and create all possible IP addresses from them. For example,

for a given string "1902426"

The result should be

"1.90.24.26" "1.90.242.6" "19.0.24.26" "19.0.242.6" "190.2.4.26" "190.2.42.6" "190.24.2.6"

Ofcourse you cannot have anything with a leading "0", like "19.02.42.26"

Zorrin Spiegler
+2  A: 
public static IEnumerable<IEnumerable<T>> SplitEvery<T>(this IEnumerable<T> values, int n)
{
    var ls = values.Take(n);
    var rs = values.Skip(n);
    return ls.Any() ?
        Cons(ls, SplitEvery(rs, n)) : 
        Enumerable.Empty<IEnumerable<T>>();
}

public static IEnumerable<T> Cons<T>(T x, IEnumerable<T> xs)
{
    yield return x;
    foreach (var xi in xs)
        yield return xi;
}
HoloEd