Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
349 views
in Technique[技术] by (71.8m points)

c# - Split string into list of N-length strings using LINQ

I know the concept of String.Split has been addressed before with a multitude of different approaches, but I am specifically interested in a LINQ solution to this question.

I've attempted to write an extension class to handle the split, but both attempts have some major issues. So for the following:

string s = "ABCDEFGHIJKLMNOPQRSTUVWX";
var results = s.SplitEvery(4);

I would want a list like: { "ABCD", "EFGH", "IJKL", "MNOP", "QRST", "UVWX" }

Here is my extension class:

public static class Extensions
{
    public static List<string> SplitEvery(this string s, int n)
    {
        List<string> list = new List<string>();

        var Attempt1 = s.Select((c, i) => i % n== 0 ? s.Substring(i, n) : "|").Where(x => x != "|").ToList();

        var Attempt2 = s.Where((c, i) => i % n== 0).Select((c, i) => s.Substring(i, n)).ToList();

        return list;
    }
}

Attempt 1 inserts a dummy string "|" every time the condition isn't met, then removes all instances of the dummy string to create the final list. It works, but creating the bad strings seems like an unnecessary extra step. Furthermore, this attempt fails if the string isn't evenly divisible by n.

Attempt 2 was me trying to select only substrings where the index was divisible by N, but the 'i' value in the Select statement doesn't correspond to the 'i' value in the Where statement, so I get results like: { "ABCD", "BCDE", etc... }

I feel like I'm close to a good solution, but could use a helpful nudge in the right direction. Any suggestions?

[Edit]

I ended up going with a combination of suggestions to handle my string-splitter. It might not be the fastest, but as a newbie to LINQ, this implementation was the most succinct and easy for me to understand.

public static List<string> SplitEvery(this string s, int size)
{
    return s.Select((x, i) => i)
        .Where(i => i % size == 0)
        .Select(i => String.Concat(s.Skip(i).Take(size))).ToList();
}

Thanks for all the excellent suggestions.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
string s = "ABCDEFGHIJKLMNOPQRSTUVWX";
var results = s.Select((c, i) => new { c, i })
            .GroupBy(x => x.i / 4)
            .Select(g => String.Join("",g.Select(y=>y.c)))
            .ToList();

You can also use morelinq's batch

var res = s.Batch(4).Select(x => String.Join("", x)).ToList();

If you don't mind using side effects, this is possible too

var res2 = s.SplitEvery(4).ToList();

public static IEnumerable<string> SplitEvery(this string s, int n)
{
    int index = 0;
    return s.GroupBy(_=> index++/n).Select(g => new string(g.ToArray()));
}

And Of course every string operation question deserves a Regex answer :)

var res3 = Regex.Split(s, @"(?<=G.{4})");

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...