split a comma-separated string and add Quotes in C# - elegant solution

Viewed 1500

I have a string looking like this:

var v = "10,14,18,21" 

and would like to use it as something looking like this:

'10', '14', '18', '21'

I have a written a function which splits the values by comma and add them back together as a string. Additionally I remove the last , from the result string.

I put everything in a function called prep for testing.

The function does, what I want it to do. However, I was wondering if there is a more elegant way to achieve the same result. Here's what I came up with:

public static string prep(string s) {
    string res = "";

    List<string> list = s.Split(',').ToList<string>();

    foreach(var item in list) 
        res += "'" + item + "',";

    res = res.TrimEnd(',');

    return res;
}
7 Answers

You could use string.Join() here:

var result = string.Join(", ", v.Split(",").Select(x => $"'{x}'"));

Console.WriteLine(result);
// '10', '14', '18', '21'

Which basically concatenates the items by ", ", then projects single quotes around each string with Enumerable.Select() from LINQ.

You can also add single quotes without $ - string interpolation:

var result = string.Join(", ", v.Split(",").Select(x => "'" + x + "'"));

As @Racil Hilan helpfully pointed out in the comments, we don't need LINQ here and can just surround the result with "'" and join on "', '":

var result = "'" + string.Join("', '", v.Split(",")) + "'";

Have you considered this?

var v = "10,14,18,21";
var r = $"'{v.Replace(",", "', '")}'";

That gives: '10', '14', '18', '21'

You can try regular expressions:

using System.Text.RegularExpressions;

...

string result = Regex.Replace(v, "[^,]+", " '$0'");

here we wrap every item between commas into single quotes.

Edit: As juharr pointed out in the comments, we have extra space at the beginning of the result string. We can either

remove it:

result = Regex.Replace(v, "[^,]+", " '$0'").TrimStart();

Or prevent it:

string result = Regex
 .Replace(v, "[^,]+", m => $"{(m.Index > 0 ? " ":"")}'{m.Value}'");

One way is to use Select on the result of Split, then string.Join:

public static string prep(string s) {
    var array = s.Split(',');
    // Select takes a lambda that tells it what to do with each item in the array
    var quotesAdded = array.Select(x => $"'{x}'");
    var result = string.Join(", ", quotesAdded);
    return result;
}

Or all in an expression-bodied member:

public static string prep(string s) => string.Join(", ",
    s.Split(',').Select(x => $"'{x}'")
);

Just for the heck of it I wrote some code to test out the various methods here to see how they fair against each other with different length strings. Feel free to add any other variations to this to find out for yourself which one is fastest and to see how it scales with larger strings.

Note: I gave up on a string with 10,000 comma separated items because the Aggregate method was taking a very long time to complete.

private static readonly Random Rand = new Random();

private static void Main(string[] args)
{
    for (int size = 10; size <= 1000; size *= 10)
    {
        var input = GenerateInput(size);

        Console.WriteLine($"Size {size}:");
        Console.WriteLine("Average          Total            Method");
        Tester(input, AddSingleQuotesRegExNotCompiled, nameof(AddSingleQuotesRegExNotCompiled));
        Tester(input, AddSingleQuotesRegExCompiled, nameof(AddSingleQuotesRegExCompiled));
        Tester(input, AddSingleQuotesStringReplace, nameof(AddSingleQuotesStringReplace));
        Tester(input, AddSingleQuotesJoinSplitSelectWithInterpolation, nameof(AddSingleQuotesJoinSplitSelectWithInterpolation));
        Tester(input, AddSingleQuotesJoinSplitSelectWithoutInterpolation, nameof(AddSingleQuotesJoinSplitSelectWithoutInterpolation));
        Tester(input, AddSingleQuotesJoinSplit, nameof(AddSingleQuotesJoinSplit));
        Tester(input, AddSingleQuotesSplitSelectAggregate, nameof(AddSingleQuotesSplitSelectAggregate));

        Console.WriteLine();
    }

    Console.ReadLine();
}


public static void Tester(string input, Func<string, string> func, string name)
{
    var sw = Stopwatch.StartNew();
    for (int i = 0; i < 10000; i++)
    {
        func(input);
    }

    sw.Stop();

    Console.Write($"{sw.Elapsed/10000} {sw.Elapsed} {name}");
    Console.WriteLine();
}

public static string GenerateInput(int count)
{
    var builder = new StringBuilder();
    while (count-- > 0)
    {
        builder.Append(Rand.Next(100));
        if (count > 0)
            builder.Append(',');
    }

    return builder.ToString();
}

private static Regex addComma = new Regex("[^,]+", RegexOptions.Compiled);

public static string AddSingleQuotesRegExCompiled(string input) => 
    addComma.Replace(input, "'$0'");
public static string AddSingleQuotesRegExNotCompiled(string input) => 
    Regex.Replace(input, "[^,]+", " '$0'");
public static string AddSingleQuotesStringReplace(string input) => 
    $"'{input.Replace(",", ", ")}'";
public static string AddSingleQuotesJoinSplitSelectWithInterpolation(string input) => 
    string.Join(", ", input.Split(",").Select(x => $"'{x}'"));
public static string AddSingleQuotesJoinSplitSelectWithoutInterpolation(string input) => 
    string.Join(", ", input.Split(",").Select(x => "'" + x + "'"));
public static string AddSingleQuotesJoinSplit(string input) => 
    "'" + string.Join("', '", input.Split(",")) + "'";
public static string AddSingleQuotesSplitSelectAggregate(string input) => 
    input.Split(',')
        .Select(m => "'" + m + "'")
        .Aggregate((tot,next) => tot + "," + next);
}

with the following results

Size 10:
Average          Total            Method
00:00:00.0000053 00:00:00.0526194 AddSingleQuotesRegExNotCompiled
00:00:00.0000031 00:00:00.0309486 AddSingleQuotesRegExCompiled
00:00:00.0000002 00:00:00.0018592 AddSingleQuotesStringReplace
00:00:00.0000017 00:00:00.0169309 AddSingleQuotesJoinSplitSelectWithInterpolation
00:00:00.0000008 00:00:00.0084822 AddSingleQuotesJoinSplitSelectWithoutInterpolation
00:00:00.0000004 00:00:00.0039672 AddSingleQuotesJoinSplit
00:00:00.0000010 00:00:00.0102010 AddSingleQuotesSplitSelectAggregate

Size 100:
Total            Average          Method
00:00:00.0000239 00:00:00.2394021 AddSingleQuotesRegExNotCompiled
00:00:00.0000163 00:00:00.1628607 AddSingleQuotesRegExCompiled
00:00:00.0000015 00:00:00.0149009 AddSingleQuotesStringReplace
00:00:00.0000065 00:00:00.0650797 AddSingleQuotesJoinSplitSelectWithInterpolation
00:00:00.0000069 00:00:00.0693588 AddSingleQuotesJoinSplitSelectWithoutInterpolation
00:00:00.0000034 00:00:00.0338554 AddSingleQuotesJoinSplit
00:00:00.0000129 00:00:00.1287369 AddSingleQuotesSplitSelectAggregate

Size 1000:
Total            Average          Method
00:00:00.0002089 00:00:02.0892826 AddSingleQuotesRegExNotCompiled
00:00:00.0001607 00:00:01.6066026 AddSingleQuotesRegExCompiled
00:00:00.0000144 00:00:00.1444781 AddSingleQuotesStringReplace
00:00:00.0000578 00:00:00.5776627 AddSingleQuotesJoinSplitSelectWithInterpolation
00:00:00.0000580 00:00:00.5801025 AddSingleQuotesJoinSplitSelectWithoutInterpolation
00:00:00.0000296 00:00:00.2957712 AddSingleQuotesJoinSplit
00:00:00.0005631 00:00:05.6307457 AddSingleQuotesSplitSelectAggregate

Just another approach to solve this problem (without using LINQ):

public static string prep(string s) =>
    "'" + string.Join("', '", s.Split(",")) + "'";

I prefer to use aggregate

    string a = "1,2,3,4,5";
    string c = a.Split(',').Select(m => "'" + m + "'").Aggregate((tot,next) => tot + "," + next);
Related