110

I have an array of integers:

int[] number = new int[] { 2,3,6,7 };

What is the easiest way of converting these into a single string where the numbers are separated by a character (like: "2,3,6,7")?

I'm using C# and .NET 3.5.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Riri
  • 11,501
  • 14
  • 63
  • 88
  • 4
    SO rocks! I got these 3 excellent answers within 10 minutes on a Sunday! – Riri Sep 28 '08 at 13:54
  • 4
    As of `.NET 4.0` there are methods that take an array of objects and an IEnumerable so you can just do `string.join(",", number)`. I know the question specifies .NET 3.5 so I didn't make this an answer, but it comes up in searches that don't specify a version and knowing it's possible in 4.0 could help someone. – Jason Goemaat Feb 23 '15 at 21:06

11 Answers11

173
var ints = new int[] {1, 2, 3, 4, 5};
var result = string.Join(",", ints.Select(x => x.ToString()).ToArray());
Console.WriteLine(result); // prints "1,2,3,4,5"

As of (at least) .NET 4.5,

var result = string.Join(",", ints.Select(x => x.ToString()).ToArray());

is equivalent to:

var result = string.Join(",", ints);

I see several solutions advertise usage of StringBuilder. Someone complains that the Join method should take an IEnumerable argument.

I'm going to disappoint you :) String.Join requires an array for a single reason - performance. The Join method needs to know the size of the data to effectively preallocate the necessary amount of memory.

Here is a part of the internal implementation of String.Join method:

// length computed from length of items in input array and length of separator
string str = FastAllocateString(length);
fixed (char* chRef = &str.m_firstChar) // note than we use direct memory access here
{
    UnSafeCharBuffer buffer = new UnSafeCharBuffer(chRef, length);
    buffer.AppendString(value[startIndex]);
    for (int j = startIndex + 1; j <= num2; j++)
    {
        buffer.AppendString(separator);
        buffer.AppendString(value[j]);
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
aku
  • 122,288
  • 32
  • 173
  • 203
33

Although the OP specified .NET 3.5, people wanting to do this in .NET 2.0 with C# 2.0 can do this:

string.Join(",", Array.ConvertAll<int, String>(ints, Convert.ToString));

I find there are a number of other cases where the use of the Convert.xxx functions is a neater alternative to a lambda, although in C# 3.0 the lambda might help the type-inferencing.

A fairly compact C# 3.0 version which works with .NET 2.0 is this:

string.Join(",", Array.ConvertAll(ints, item => item.ToString()))
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Will Dean
  • 39,055
  • 11
  • 90
  • 118
11

One mixture of the two approaches would be to write an extension method on IEnumerable<T> which used a StringBuilder. Here's an example, with different overloads depending on whether you want to specify the transformation or just rely on plain ToString. I've named the method "JoinStrings" instead of "Join" to avoid confusion with the other type of Join. Perhaps someone can come up with a better name :)

using System;
using System.Collections.Generic;
using System.Text;

public static class Extensions
{
    public static string JoinStrings<T>(this IEnumerable<T> source, 
                                        Func<T, string> projection, string separator)
    {
        StringBuilder builder = new StringBuilder();
        bool first = true;
        foreach (T element in source)
        {
            if (first)
            {
                first = false;
            }
            else
            {
                builder.Append(separator);
            }
            builder.Append(projection(element));
        }
        return builder.ToString();
    }

    public static string JoinStrings<T>(this IEnumerable<T> source, string separator)
    {
        return JoinStrings(source, t => t.ToString(), separator);
    }
}

class Test
{

    public static void Main()
    {
        int[] x = {1, 2, 3, 4, 5, 10, 11};

        Console.WriteLine(x.JoinStrings(";"));
        Console.WriteLine(x.JoinStrings(i => i.ToString("X"), ","));
    }
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Nice solution! You dont need the projection parameter though, you can just write x.Select(i => i.ToString("X")).JoinStrings(";") which is more idiomatic. – JacquesB Sep 28 '08 at 18:45
  • Yes, I thought about that afterwards. Occasionally it's nice to be able to specify it all in one go, but it's definitely more elegant to split the operations :) – Jon Skeet Sep 28 '08 at 18:52
8
String.Join(";", number.Select(item => item.ToString()).ToArray());

We have to convert each of the items to a String before we can join them, so it makes sense to use Select and a lambda expression. This is equivalent to map in some other languages. Then we have to convert the resulting collection of string back to an array, because String.Join only accepts a string array.

The ToArray() is slightly ugly I think. String.Join should really accept IEnumerable<String>, there is no reason to restrict it to only arrays. This is probably just because Join is from before generics, when arrays were the only kind of typed collection available.

JacquesB
  • 41,662
  • 13
  • 71
  • 86
5

If your array of integers may be large, you'll get better performance using a StringBuilder. E.g.:

StringBuilder builder = new StringBuilder();
char separator = ',';
foreach(int value in integerArray)
{
    if (builder.Length > 0) builder.Append(separator);
    builder.Append(value);
}
string result = builder.ToString();

Edit: When I posted this I was under the mistaken impression that "StringBuilder.Append(int value)" internally managed to append the string representation of the integer value without creating a string object. This is wrong: inspecting the method with Reflector shows that it simply appends value.ToString().

Therefore the only potential performance difference is that this technique avoids one array creation, and frees the strings for garbage collection slightly sooner. In practice this won't make any measurable difference, so I've upvoted this better solution.

Community
  • 1
  • 1
Joe
  • 122,218
  • 32
  • 205
  • 338
  • Have you measured it to be faster? String.Join uses a StringBuilder also. – JacquesB Sep 28 '08 at 14:37
  • Yes, but you first need to convert the whole thing to an array, which is far from ideal. In particular, it means that you need to have all the converted strings in memory at the same time, *before* you start building the resulting string. – Jon Skeet Sep 28 '08 at 14:46
  • OTOH String.Join precalculates the size of the StringBuilder buffer so it avoids resizing. So it might be faster even if it requires more memory. – JacquesB Sep 28 '08 at 20:08
5

The question is for "easiest way of converting these in to a single string where the number are separated by a character".

The easiest way is:

int[] numbers = new int[] { 2,3,6,7 };
string number_string = string.Join(",", numbers);
// do whatever you want with your exciting new number string

This only works in .NET 4.0+.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
WebMasterP
  • 518
  • 4
  • 8
  • This is not valid as string.Join method takes only an array of strings. Have a look here http://msdn.microsoft.com/en-us/library/tk0xe5h0.aspx – ppolyzos Dec 05 '11 at 14:17
  • 1
    It is an overloaded method: http://msdn.microsoft.com/en-us/library/dd988350 I just copied the code I wrote into a new console app, added a Console.WriteLine and this is the output: 2,3,6,7 – WebMasterP Aug 28 '12 at 01:26
  • 1
    I think this is available in only .net 4 – Govind Malviya Oct 27 '12 at 09:10
  • Requires an object array (or string array), not an int array. Will give a "call is ambiguous" error. – LarryBud Apr 30 '15 at 14:19
3
ints.Aggregate("", ( str, n ) => str +","+ n ).Substring(1);

I also thought there was a simpler way.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
void
  • 769
  • 6
  • 7
3

In .NET 4.0, string join has an overload for params object[], so it's as simple as:

int[] ids = new int[] { 1, 2, 3 };
string.Join(",", ids);

Example

int[] ids = new int[] { 1, 2, 3 };
System.Data.Common.DbCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM some_table WHERE id_column IN (@bla)");
cmd.CommandText = cmd.CommandText.Replace("@bla",  string.Join(",", ids));

In .NET 2.0, it's a tiny little bit more difficult, since there's no such overload. So you need your own generic method:

public static string JoinArray<T>(string separator, T[] inputTypeArray)
{
    string strRetValue = null;
    System.Collections.Generic.List<string> ls = new System.Collections.Generic.List<string>();

    for (int i = 0; i < inputTypeArray.Length; ++i)
    {
        string str = System.Convert.ToString(inputTypeArray[i], System.Globalization.CultureInfo.InvariantCulture);

        if (!string.IsNullOrEmpty(str))
        {
            // SQL-Escape
            // if (typeof(T) == typeof(string))
            //    str = str.Replace("'", "''");

            ls.Add(str);
        } // End if (!string.IsNullOrEmpty(str))

    } // Next i

    strRetValue= string.Join(separator, ls.ToArray());
    ls.Clear();
    ls = null;

    return strRetValue;
}

In .NET 3.5, you can use extension methods:

public static class ArrayEx
{

    public static string JoinArray<T>(this T[] inputTypeArray, string separator)
    {
        string strRetValue = null;
        System.Collections.Generic.List<string> ls = new System.Collections.Generic.List<string>();

        for (int i = 0; i < inputTypeArray.Length; ++i)
        {
            string str = System.Convert.ToString(inputTypeArray[i], System.Globalization.CultureInfo.InvariantCulture);

            if (!string.IsNullOrEmpty(str))
            {
                // SQL-Escape
                // if (typeof(T) == typeof(string))
                //    str = str.Replace("'", "''");

                ls.Add(str);
            } // End if (!string.IsNullOrEmpty(str))

        } // Next i

        strRetValue= string.Join(separator, ls.ToArray());
        ls.Clear();
        ls = null;

        return strRetValue;
    }

}

So you can use the JoinArray extension method.

int[] ids = new int[] { 1, 2, 3 };
string strIdList = ids.JoinArray(",");

You can also use that extension method in .NET 2.0, if you add the ExtensionAttribute to your code:

// you need this once (only), and it must be in this namespace
namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
    public sealed class ExtensionAttribute : Attribute {}
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
2

I agree with the lambda expression for readability and maintainability, but it will not always be the best option. The downside to using both the IEnumerable/ToArray and StringBuilder approaches is that they have to dynamically grow a list, either of items or characters, since they do not know how much space will be needed for the final string.

If the rare case where speed is more important than conciseness, the following is more efficient.

int[] number = new int[] { 1, 2, 3, 4, 5 };
string[] strings = new string[number.Length];
for (int i = 0; i < number.Length; i++)
  strings[i] = number[i].ToString();
string result = string.Join(",", strings);
DocMax
  • 12,094
  • 7
  • 44
  • 44
1

You can do

ints.ToString(",")
ints.ToString("|")
ints.ToString(":")

Check out

Separator Delimited ToString for Array, List, Dictionary, Generic IEnumerable

Ray Lu
  • 26,208
  • 12
  • 60
  • 59
1

Forget about .NET 3.5 and use the following code in .NET Core:

var result = string.Join(",", ints);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131