nop
nop

Reputation: 6311

Get the pre-last element of a string split by spaces

Input examples:

7 9 12 16 18 21 25 27 30 34 36 39 43 45 48 52 54 57 61 
7 9 12 16 18 21 25 27 30 34 36 39 43 45 48 52 54 57 ... 75 79

Note that it ends with a space.

I want to get 57 in the first case and 75 in the second case as integer. I tried with the following:

Convert.ToInt32(Shorten(sequence).Split(' ').ElementAt(sequence.Length - 2));

The problem is that sequence.Length is not really the right index.

Upvotes: 1

Views: 1518

Answers (3)

Charles
Charles

Reputation: 3061

How about something that doesn't use strings at all.

public static int? SplitReverseInt(this string str, int ixFromBack)
{
    var inWord = false;
    var wEnd = 0;
    var found = 0;

    for (int i = str.Length - 1; i >= 0; i--)
    {
        var charr = str[i];
        if (char.IsWhiteSpace(charr))
        {
            // we found the beginning of a word
            if (inWord)
            {
                if (found == ixFromBack)
                {
                    var myInt = 0;
                    for (int j = i+1; j <= wEnd; j++)
                        myInt = (myInt * 10 + str[j] - '0');

                    return myInt;
                }

                inWord = false;
                found++;
            }
        }
        else
        {
            if (!inWord)
            {
                wEnd = i;
                inWord = true;
            }
        }
    }

    // word (number) is at the beginning of the string
    if (inWord && found == ixFromBack)
    {
        var myInt = 0;
        for (int j = 0; j <= wEnd; j++)
            myInt = (myInt * 10 + str[j] - '0');

        return myInt;
    }

    return null;
}

Performance is about 10 times faster on the example strings. This only loops from the back, and only fetches one number, it doesnt create substrings or an array of strings we don't need.

Use like this:

var numberFromBack = SplitReverseInt(input, 1);

Upvotes: 0

Christoph L&#252;tjen
Christoph L&#252;tjen

Reputation: 5804

Based on maccettura's answer, in C# 8 you can simplify index acces like so

var input = "1 2 3";
var parts = input.Split(' ', StringSplitOptions.RemoveEmptyEntries);
var value = parts.Length >= 2 ? Convert.ToInt32(parts[^2]) : null;

Upvotes: 2

maccettura
maccettura

Reputation: 10818

You can use the overload for Split() and pass the RemoveEmptyEntires enum:

string input = "7 9 12 16 18 21 25 27 30 34 36 39 43 45 48 52 54 57 61 ";
var splitInput = input.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
var inputInt = Convert.ToInt32(splitInput[splitInput.Length - 2]);
// inputInt is 57

Doing it this way allows your last element to actually be what you want.

Fiddle here

Upvotes: 7

Related Questions