int array to string
Asked Answered
D

13

81

In C#, I have an array of ints, containing digits only. I want to convert this array to string.

Array example:

int[] arr = {0,1,2,3,0,1};

How can I convert this to a string formatted as: "012301"?

Danby answered 30/11, 2009 at 22:20 Comment(0)
D
127

at.net 3.5 use:

 String.Join("", new List<int>(array).ConvertAll(i => i.ToString()).ToArray());

at.net 4.0 or above use: (see @Jan Remunda's answer)

 string result = string.Join("", array);
Diminished answered 30/11, 2009 at 22:22 Comment(2)
There is very much unnecessary code :) Try just: String.Join("", new int[] {0,1,2,3,0,1});Becket
It's implementation handles null values and also converts all to string: referencesource.microsoft.com/#mscorlib/system/string.cs#125Becket
B
42

You can simply use String.Join function, and as separator use string.Empty because it uses StringBuilder internally.

string result = string.Join(string.Empty, new []{0,1,2,3,0,1});

E.g.: If you use semicolon as separator, the result would be 0;1;2;3;0;1.

It actually works with null separator, and second parameter can be enumerable of any objects, like:

string result = string.Join(null, new object[]{0,1,2,3,0,"A",DateTime.Now});
Becket answered 5/4, 2012 at 7:47 Comment(1)
This solution is for .NET 4.0 and higherBecket
D
27

I realize my opinion is probably not the popular one, but I guess I have a hard time jumping on the Linq-y band wagon. It's nifty. It's condensed. I get that and I'm not opposed to using it where it's appropriate. Maybe it's just me, but I feel like people have stopped thinking about creating utility functions to accomplish what they want and instead prefer to litter their code with (sometimes) excessively long lines of Linq code for the sake of creating a dense 1-liner.

I'm not saying that any of the Linq answers that people have provided here are bad, but I guess I feel like there is the potential that these single lines of code can start to grow longer and more obscure as you need to handle various situations. What if your array is null? What if you want a delimited string instead of just purely concatenated? What if some of the integers in your array are double-digit and you want to pad each value with leading zeros so that the string for each element is the same length as the rest?

Taking one of the provided answers as an example:

        result = arr.Aggregate(string.Empty, (s, i) => s + i.ToString());

If I need to worry about the array being null, now it becomes this:

        result = (arr == null) ? null : arr.Aggregate(string.Empty, (s, i) => s + i.ToString());

If I want a comma-delimited string, now it becomes this:

        result = (arr == null) ? null : arr.Skip(1).Aggregate(arr[0].ToString(), (s, i) => s + "," + i.ToString());

This is still not too bad, but I think it's not obvious at a glance what this line of code is doing.

Of course, there's nothing stopping you from throwing this line of code into your own utility function so that you don't have that long mess mixed in with your application logic, especially if you're doing it in multiple places:

    public static string ToStringLinqy<T>(this T[] array, string delimiter)
    {
        // edit: let's replace this with a "better" version using a StringBuilder
        //return (array == null) ? null : (array.Length == 0) ? string.Empty : array.Skip(1).Aggregate(array[0].ToString(), (s, i) => s + "," + i.ToString());
        return (array == null) ? null : (array.Length == 0) ? string.Empty : array.Skip(1).Aggregate(new StringBuilder(array[0].ToString()), (s, i) => s.Append(delimiter).Append(i), s => s.ToString());
    }

But if you're going to put it into a utility function anyway, do you really need it to be condensed down into a 1-liner? In that case why not throw in a few extra lines for clarity and take advantage of a StringBuilder so that you're not doing repeated concatenation operations:

    public static string ToStringNonLinqy<T>(this T[] array, string delimiter)
    {
        if (array != null)
        {
            // edit: replaced my previous implementation to use StringBuilder
            if (array.Length > 0)
            {
                StringBuilder builder = new StringBuilder();

                builder.Append(array[0]);
                for (int i = 1; i < array.Length; i++)
                {
                    builder.Append(delimiter);
                    builder.Append(array[i]);
                }

                return builder.ToString()
            }
            else
            {
                return string.Empty;
            }
        }
        else
        {
            return null;
        }
    }

And if you're really so concerned about performance, you could even turn it into a hybrid function that decides whether to do string.Join or to use a StringBuilder depending on how many elements are in the array (this is a micro-optimization, not worth doing in my opinion and possibly more harmful than beneficial, but I'm using it as an example for this problem):

    public static string ToString<T>(this T[] array, string delimiter)
    {
        if (array != null)
        {
            // determine if the length of the array is greater than the performance threshold for using a stringbuilder
            // 10 is just an arbitrary threshold value I've chosen
            if (array.Length < 10)
            {
                // assumption is that for arrays of less than 10 elements
                // this code would be more efficient than a StringBuilder.
                // Note: this is a crazy/pointless micro-optimization.  Don't do this.
                string[] values = new string[array.Length];

                for (int i = 0; i < values.Length; i++)
                    values[i] = array[i].ToString();

                return string.Join(delimiter, values);
            }
            else
            {
                // for arrays of length 10 or longer, use a StringBuilder
                StringBuilder sb = new StringBuilder();

                sb.Append(array[0]);
                for (int i = 1; i < array.Length; i++)
                {
                    sb.Append(delimiter);
                    sb.Append(array[i]);
                }

                return sb.ToString();
            }
        }
        else
        {
            return null;
        }
    }

For this example, the performance impact is probably not worth caring about, but the point is that if you are in a situation where you actually do need to be concerned with the performance of your operations, whatever they are, then it will most likely be easier and more readable to handle that within a utility function than using a complex Linq expression.

That utility function still looks kind of clunky. Now let's ditch the hybrid stuff and do this:

    // convert an enumeration of one type into an enumeration of another type
    public static IEnumerable<TOut> Convert<TIn, TOut>(this IEnumerable<TIn> input, Func<TIn, TOut> conversion)
    {
        foreach (TIn value in input)
        {
            yield return conversion(value);
        }
    }

    // concatenate the strings in an enumeration separated by the specified delimiter
    public static string Delimit<T>(this IEnumerable<T> input, string delimiter)
    {
        IEnumerator<T> enumerator = input.GetEnumerator();

        if (enumerator.MoveNext())
        {
            StringBuilder builder = new StringBuilder();

            // start off with the first element
            builder.Append(enumerator.Current);

            // append the remaining elements separated by the delimiter
            while (enumerator.MoveNext())
            {
                builder.Append(delimiter);
                builder.Append(enumerator.Current);
            }

            return builder.ToString();
        }
        else
        {
            return string.Empty;
        }
    }

    // concatenate all elements
    public static string ToString<T>(this IEnumerable<T> input)
    {
        return ToString(input, string.Empty);
    }

    // concatenate all elements separated by a delimiter
    public static string ToString<T>(this IEnumerable<T> input, string delimiter)
    {
        return input.Delimit(delimiter);
    }

    // concatenate all elements, each one left-padded to a minimum length
    public static string ToString<T>(this IEnumerable<T> input, int minLength, char paddingChar)
    {
        return input.Convert(i => i.ToString().PadLeft(minLength, paddingChar)).Delimit(string.Empty);
    }

Now we have separate and fairly compact utility functions, each of which are arguable useful on their own.

Ultimately, my point is not that you shouldn't use Linq, but rather just to say don't forget about the benefits of creating your own utility functions, even if they are small and perhaps only contain a single line that returns the result from a line of Linq code. If nothing else, you'll be able to keep your application code even more condensed than you could achieve with a line of Linq code, and if you are using it in multiple places, then using a utility function makes it easier to adjust your output in case you need to change it later.

For this problem, I'd rather just write something like this in my application code:

        int[] arr = { 0, 1, 2, 3, 0, 1 };

        // 012301
        result = arr.ToString<int>();

        // comma-separated values
        // 0,1,2,3,0,1
        result = arr.ToString(",");

        // left-padded to 2 digits
        // 000102030001
        result = arr.ToString(2, '0');
Diagram answered 1/12, 2009 at 1:3 Comment(7)
You had me right up to the point where you created a string array and populated it just so you could call string.join. It's a waste of resources when you can take advantage of deferred execution and skip the string array completely. The code in Join isn't rocket science, it's a trivial exercise to write a generic 'Join' or 'Delimit' method (extension method if you must) that iterates over an Enumerator and builds the delimited string. I get the general point and agree, but I can't upvote because of the dumb sample code. Sorry DudeEncephalitis
P.S. You can use LINQ and get the power of deferred execution without cramming it all on one line. I agree that there are too many crammed LINQy examples out there. It reminds me of waaaaaaaaay back in the day when learning C, that folks would write one line WTF code to copy a string "while(*dst++ = *src++);" not because it was better/faster/More readable (definitely not the last), but because they COULD and it made them (OK then, me too) feel smart. Of course it should be written more clearly, regardless of how smart or not smart it makes you feel. Sorry for running on mate.Encephalitis
Thanks for the feedback. I won't claim to be an expert on the subject. However, I did test the following line of code, and it executed noticeably slower than an implementation that used an array: res = arr.Aggregate(string.Empty, (s, i) => s + i.ToString()); For 1 million iterations of concatenating an int[] of length 100, this took about 60 seconds vs 40 seconds using an array. This seemed inefficient to me because I assume it does a concatenation on each iteration, whereas string.Join only does one concatenation. Please let me know if there is a more efficient way that I am missing.Nonoccurrence
This following code seems to execute about on par with two other implementations that I tried, both of which used Array.ForEach, one with an array and string.Join, the other with a StringBuilder: int i = 0; res = arr.Aggregate(new string[arr.Length], (s, x) => { s[i++] = x.ToString(); return s; }, s => string.Join(string.Empty, s));Nonoccurrence
By the way, I believe that you can only take advantage of deferred execution if you are using a function that returns a set of results (such as Intersect), but if you're using a function that returns a single result (like Aggregate), then the code will execute over all elements immediately. In this case, since we're attempting to return a single string value, I don't think deferred execution can be applied.Nonoccurrence
Thanks for the comments, a few points: 1) No point even talking about my solution if performance is a real concern, but in 90% of most work, performance probably isn't a concern. I start at the common case. 2) Generally I idiomatically return empty collections instead of nulls to reduce clutter, for just the reason you've illustrated in your early examples. 3) You're right about (the lack of) deferred execution. 4) I think it's just a matter of taste. Your final solution is probably clearer to people who come to C# from C++; I prefer a more physically concise and functional approach.Raid
I totally agree, especially with the checking for null's functionality which bloats and makes LINQ very confusing. Might give you a buzz while writing the 1-liner, but in 12 months time the next developer is thinking a word that he couldn't say on radio.Susurrant
T
20

To avoid the creation of an extra array you could do the following.

var builder = new StringBuilder();
Array.ForEach(arr, x => builder.Append(x));
var res = builder.ToString();
Tarsus answered 30/11, 2009 at 22:23 Comment(2)
Haven't verified this, but you may be able to pass builder.Append instead of the lambda expression since builder.Append matches the signature of the expected delegate in Array.ForEach.Distrain
Steve, good idea, but that won't work because ForEach() expects void, and Append() returns StringBuilder.Team
R
10
string result = arr.Aggregate("", (s, i) => s + i.ToString());

(Disclaimer: If you have a lot of digits (hundreds, at least) and you care about performance, I suggest eschewing this method and using a StringBuilder, as in JaredPar's answer.)

Raid answered 30/11, 2009 at 22:22 Comment(4)
This is actually deceptively expensive. This has "telescoping" memory requirements, so for anything over a small array is not ideal. Sorry.Derisible
This is fine for small arrays but the fact that it is building a string on each iteration would be a concern with larger arrays or where this code is called a lot.Expedite
That's absolutely true and if performance is a concern then you should not do this. If there are just a handful of digits, though, I'd write this for the sake of clarity and concision (although I'm sure tastes may vary.)Raid
Yes, Aggregate() is right, but you should use StringBuilder. See my answer.Team
D
5

You can do:

 int[] arr = {0,1,2,3,0,1};
 string results = string.Join("",arr.Select(i => i.ToString()).ToArray());

That gives you your results.

Density answered 30/11, 2009 at 22:22 Comment(0)
M
5

I like using StringBuilder with Aggregate(). The "trick" is that Append() returns the StringBuilder instance itself:

var sb = arr.Aggregate( new StringBuilder(), ( s, i ) => s.Append( i ) );
var result = sb.ToString();     
Mujik answered 30/11, 2009 at 22:36 Comment(0)
E
1

I've left this here for posterity but don't recommend its use as it's not terribly readable. This is especially true now that I've come back to see if after a period of some time and have wondered what I was thinking when I wrote it (I was probably thinking 'crap, must get this written before someone else posts an answer'.)

string s = string.Concat(arr.Cast<object>().ToArray());
Expedite answered 30/11, 2009 at 22:22 Comment(2)
+1. This is the simplest way if you don't need any delimiter, which is what the OP asked for. Of course there is no overload to support a delimiter...Culinary
(I think in this form, however, it will be seriously outperformed by a simple StringBuilder solution.)Expedite
T
1
string.Join("", (from i in arr select i.ToString()).ToArray())

In the .NET 4.0 the string.Join can use an IEnumerable<string> directly:

string.Join("", from i in arr select i.ToString())
Temporary answered 30/11, 2009 at 22:27 Comment(0)
T
1

The most efficient way is not to convert each int into a string, but rather create one string out of an array of chars. Then the garbage collector only has one new temp object to worry about.

int[] arr = {0,1,2,3,0,1};
string result = new string(Array.ConvertAll<int,char>(arr, x => Convert.ToChar(x + '0')));
Tut answered 1/12, 2009 at 23:11 Comment(0)
T
1

This is a roundabout way to go about it its not much code and easy for beginners to understand

    int[] arr = {0,1,2,3,0,1};
    string joined = "";
    foreach(int i in arr){
        joined += i.ToString();
    }
    int number = int.Parse(joined);
    
Terresaterrestrial answered 27/10, 2021 at 6:22 Comment(0)
I
0

If this is long array you could use

var sb = arr.Aggregate(new StringBuilder(), ( s, i ) => s.Append( i ), s.ToString());
Interlay answered 11/12, 2013 at 9:48 Comment(0)
S
0
// This is the original array
int[] nums = {1, 2, 3};

// This is an empty string we will end up with
string numbers = "";

// iterate on every char in the array
foreach (var item in nums)
{
    // add the char to the empty string
    numbers += Convert.ToString(item);
}

// Write the string in the console
Console.WriteLine(numbers);
Samarium answered 2/10, 2021 at 12:54 Comment(1)
Code only answers are not that useful. Please explain your codeCline

© 2022 - 2024 — McMap. All rights reserved.