14

So we have ?? to parse its right-hand value for when the left hand is null. What is the equivalent for a string[].

For example

string value = "One - Two"
string firstValue = value.Split('-')[0] ?? string.Empty;
string secondValue = value.Split('-')[1] ?? string.Empty;

Above example would still crash if we would try to get a third index or if string value = "One". Because it is not null but IndexOutOfRangeException is thrown.

https://learn.microsoft.com/en-us/dotnet/api/system.indexoutofrangeexception

So what is a one-line solution to tackle the above problem? I'd like to avoid the try-catch scenario because this gives ugly code.

I want to get value out of a string[] with a string.Empty as a backup value so my string is never null.

sujith karivelil
  • 28,671
  • 6
  • 55
  • 88
Roy Berris
  • 1,502
  • 1
  • 17
  • 40
  • string secondValue = value.Split('-').Length > 1 ? value.Split('-')[1] ?? string.Empty : string.Empty; – Test12345 Jul 30 '19 at 11:33
  • `string thirdValue = value.Split('-').ElementAtOrDefault(3) ?? "";` – Dmitry Bychenko Jul 30 '19 at 11:34
  • You could use [?: operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/conditional-operator), but the question is - do you really gain much with one liner here? Saving split result into local variable is preferable. You can build an extension method which will return `""` for array if parameter is out of range instead of using indexer. – Sinatr Jul 30 '19 at 11:37

4 Answers4

19

Well, you can try Linq:

using System.Linq;

...

string thirdValue = value.Split('-').ElementAtOrDefault(2) ?? string.Empty;

However, your code has a drawback: you constantly Split the same string. I suggest extracting value.Split('-'):

string value = "One - Two"
var items = value.Split('-');

string firstValue = items.ElementAtOrDefault(0) ?? string.Empty;
string secondValue = items.ElementAtOrDefault(1) ?? string.Empty;
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
2

I suggest you create a method for this. which will accept two inputs of type string(representing the input string) and an integer(represents the specified index), and should return the split value if the specified index is available, else it will return an empty string:

string GetSubstring(string input, int index)
{
    string returnValue = String.Empty;
    string[] substrings = input.Split(new[] { "-" }, StringSplitOptions.RemoveEmptyEntries);
    returnValue = substrings.Length > index ? substrings[index] : returnValue;
    return returnValue;
}

Here is a working example for your reference

sujith karivelil
  • 28,671
  • 6
  • 55
  • 88
0

Maybe the following code will be useful

string value = "One - Two";
string firstValue = (value.Split('-').Length == 1 ? value.Split('-')[0] : null) ?? string.Empty;
string secondValue = (value.Split('-').Length == 2 ? value.Split('-')[1] : null) ?? string.Empty;
Ankit Das
  • 640
  • 4
  • 16
0

One way to achieve this is to use MoreLinq's Lead and tuple destructuring:

string value = "One - Two";
var (first, second) = value.Split('-').Lead(1, string.Empty, (x, y) => (x, y)).First();

Or, if you want a more generic approach that works for all indices:

string value = "One - Two - Three - Fourth - Fifth";
var (first, second) = value.Split('-').Skip(6).Concat(string.Empty).Lead(7, string.Empty, (x, y) => (x, y)).First();

This code will get the seventh and fourteenth entries (neither of which are there, so string.Empty will be used for both).

Another option to consider is to assign two different variables on the same line of code:

string value = "One - Two";
var split = value.Split('-');
string first = split[0] ?? string.Empty, second = split.ElementAtOrDefault(1) ?? string.Empty;

This gives you three lines of code, good performance and reasonable level of clarity and readability.

Note there is no need to use ElementOrDefault(0) - better to use [0] since Split will never return an array with no elements in it.

Another option would be to use destructuring - but that is really only useful if you are interested in contiguous entries at the start of the array (although it could be tweaked to take index parameters reasonably simply):

public static void Destructure<T>(this T[] items, T defaultValue, out T t0, out T t1)
{
    t0 = items.Length > 0 ? items[0] : defaultValue;
    t1 = items.Length > 1 ? items[1] : defaultValue;
}
mjwills
  • 23,389
  • 6
  • 40
  • 63