0

I wrote a extension method for String in a PCL Project.:

public static ICollection<string[]> SplitAt(this string input, char target, int length, StringSplitOptions opts, bool trin = false()
{
    string[] itens = input.Split(new char[] { target }, opts);
    return InternalSplitAt(itens, target, length, trim);
}

private static ICollection<string[]> InternalSplitAt(string[] itens, char target, int length, bool trim = false)
{
    var collectionToReturn = new List<string[]>();
    var targetString = target.ToString();
    do
    {
        string firstPart = string.Join(targetString, itens.Take(length));
        collectionToReturn.Add(firstPart.Split(target));
        if (trim)
        {
            itens = itens.Skip(length).Select(x => x.Trim()).ToArray();
        }
        else
        {
            itens = itens.Skip(length).ToArray();
        }
    }
    while (itens.Length >= length);

    return collectionToReturn;
}

Then I use the SplitAt method like this:

var arr = str.SplitAt('#', 34, StringSplitOption.None);

str is a String with 280474 characters.

When I call the above code in a Xamarin.Android App, it takes almost 40 seconds to complete, and in a Console Application, 1 second.

Can my code be improved in any to make it run faster on Android?

Note: That extension method is based on a code I got some time ago from another StackOverflow question I think, but I could not find it again to give proper credit.

Edit:

Explaining what I'm trying to acomplish: I have a String like that:

var str = "001#Test#002#Test#003#Test";

Doing a normal Split by #, I would get na array this:

string[] { "001", "Test", "002", "Test", "003", "Test" }

But I need it to be three different arrays, so calling that extension like this:

var arr = str.SplitAt('#', 2, StringSplitOption.None);

I got:

string[] { "001", "Test" }
string[] { "002", "Test" }
string[] { "003", "Test" }

In my real scenario, the 280474 string have 53074 of the # character, and since I'm calling the extension with 34 as the length parameter, my final output would be a ICollection with 1561 itens (53074 / 34), each being a string[34].

2 Answers2

1

Try this, I've reduced the number of operations required to complete the task. Also I've done the trim initially in case you need it, so that the code doesn't call trim multiple times. It ran about 6 times faster on my machine with ~10k of test data.

    public static ICollection<string[]> SplitAt(this string input, char target, int length, StringSplitOptions opts, bool trim = false)
    {
        var items = input.Split(new[] { target }, opts);
        if (trim) items = items.Select(x => x.Trim()).ToArray();
        return InternalSplitAt(items, length);
    }

    private static ICollection<string[]> InternalSplitAt(string[] items, int length)
    {
        var collectionToReturn = new List<string[]>();

        for (int i = 0; i < items.Length; i += length)
        {
            collectionToReturn.Add(items.Skip(i).Take(length).ToArray());
        }

        return collectionToReturn;
    }
Simon
  • 1,081
  • 9
  • 14
0

Based on @Simon's answer and @Jon Skeet's comment, I came up with a very efficient solution, that runs in 20~30 milisseconds. The array creation with ToArray and the string joining really hurt performance in that scenario.

public static ICollection<string[]> SplitAt(this string input, char target, int length, StringSplitOptions, opts = StringSplitOptions.None, bool trim = false)
{
    string[] itens = input.Split(new char[] { target }, opts);
    if (trim) itens = itens.Select(s => s.Trim()).ToArray();
    return InternalSplitAt(itens, length);
}

private static ICollection<string[]> InternalSplitAt(string[] itens, char target, int length, bool trim = false)
{
    var collectionToReturn = new List<string[]>();

    var loops = itens.Length / length;
    for (int i = 0; i < loops; i++)
    {
        var arrayToAdd = new string[length];
        Array.Copy(itens, i * length, newArray, 0, length);
        ret.Add(arrayToAdd);
    }

    return collectionToReturn;
}

Credits to this answer for the section where I take a part of the array.

Again, thanks to Simon for the helpful answer and to Jon Skeet for poiting out the possible problems in the array creation and string joining.

Community
  • 1
  • 1