int массив в строку - PullRequest
       60

int массив в строку

53 голосов
/ 01 декабря 2009

В C # у меня есть массив целых чисел, содержащий только цифры. Я хочу преобразовать этот массив в строку.

Пример массива:

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

Как я могу преобразовать это в строку в формате: "012301"?

Ответы [ 11 ]

83 голосов
/ 01 декабря 2009

at.net 3.5 использование:

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

at.net 4.0 или выше: (см. Ответ @Jan Remunda)

 string result = string.Join("", array);
27 голосов
/ 05 апреля 2012

Вы можете просто использовать функцию String.Join , а в качестве разделителя использовать string.Empty, поскольку она использует StringBuilder для внутреннего использования.

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

Например: если вы используете точку с запятой в качестве разделителя, результат будет 0;1;2;3;0;1.

На самом деле он работает с нулевым разделителем, а второй параметр может быть перечисляемым для любых объектов, например:

string result = string.Join(null, new object[]{0,1,2,3,0,"A",DateTime.Now});
24 голосов
/ 01 декабря 2009

Я понимаю, что мое мнение, вероятно, не очень популярно, но, думаю, мне тяжело прыгать на повозке Linq-y. Это изящно. Это сжато. Я понимаю это, и я не против использовать его там, где это уместно. Может быть, это только я, но я чувствую, что люди перестали думать о создании служебных функций, чтобы выполнить то, что они хотят, и вместо этого предпочитают засорять свой код (иногда) чрезмерно длинными строками кода Linq для создания плотного 1-строчного текста.

Я не говорю, что какой-либо из ответов Linq, предоставленных здесь людьми, является плохим, но я думаю, я чувствую, что существует вероятность того, что эти отдельные строки кода могут начать расти дольше и более неясными по мере необходимости. справиться с различными ситуациями. Что если ваш массив равен нулю? Что делать, если вы хотите получить строку с разделителями вместо простой конкатенации? Что, если некоторые из целых чисел в вашем массиве являются двузначными, и вы хотите заполнить каждое значение начальными нулями, чтобы длина строки для каждого элемента была такой же длины, как у остальных?

Взяв в качестве примера один из предоставленных ответов:

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

Если мне нужно беспокоиться о том, что массив равен нулю, теперь он становится таким:

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

Если я хочу строку с разделителями-запятыми, теперь она становится такой:

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

Это все еще не так уж плохо, но я думаю, с первого взгляда не очевидно, что делает эта строка кода.

Конечно, ничто не мешает вам бросить эту строку кода в вашу собственную служебную функцию, чтобы вы не смешивали этот длинный беспорядок с логикой приложения, особенно если вы делаете это в нескольких местах:

    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());
    }

Но если вы все равно собираетесь поместить его в служебную функцию, вам действительно нужно, чтобы он был сжат до 1 строки? В таком случае, почему бы не добавить несколько дополнительных строк для ясности и воспользоваться StringBuilder, чтобы не выполнять повторные операции конкатенации:

    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;
        }
    }

И если вы действительно так обеспокоены производительностью, вы можете даже превратить ее в гибридную функцию, которая решает, нужно ли делать string.Join или использовать StringBuilder в зависимости от того, сколько элементов в массиве (это микро -оптимизация, на мой взгляд не стоит делать и, возможно, более вредна, чем полезна, но я использую ее в качестве примера для этой проблемы):

    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;
        }
    }

В этом примере влияние на производительность, вероятно, не стоит того, чтобы о нем заботиться, но дело в том, что если вы находитесь в ситуации, когда вам действительно нужно заботиться о производительности ваших операций, какими бы они ни были, тогда это будет Скорее всего, будет проще и удобочитаемее справиться с этим внутри служебной функции, чем при использовании сложного выражения Linq.

Эта служебная функция все еще выглядит неуклюже. Теперь давайте отбросим гибридные вещи и сделаем так:

    // 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);
    }

Теперь у нас есть отдельные и довольно компактные служебные функции, каждая из которых может быть полезна сама по себе.

В конечном счете, я хочу сказать, что вы не должны использовать Linq, а просто сказать, что не забывайте о преимуществах создания собственных служебных функций, даже если они небольшие и, возможно, содержат только одну строку, которая возвращает результат из строки кода Linq. Если ничего другого, вы сможете сохранить код своего приложения даже более сжатым, чем вы могли бы достичь с помощью строки кода Linq, и если вы используете его в нескольких местах, то использование служебной функции облегчает настройку вывода. на случай, если вам понадобится изменить его позже.

Для этой проблемы я бы просто написал что-то вроде этого в коде моего приложения:

        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');
20 голосов
/ 01 декабря 2009

Чтобы избежать создания дополнительного массива, вы можете сделать следующее.

var builder = new StringBuilder();
Array.ForEach(arr, x => builder.Append(x));
var res = builder.ToString();
9 голосов
/ 01 декабря 2009
string result = arr.Aggregate("", (s, i) => s + i.ToString());

(Отказ от ответственности: если у вас много цифр (по крайней мере, сотен) и вы заботитесь о производительности, я предлагаю отказаться от этого метода и использовать StringBuilder, как в ответе JaredPar.)

5 голосов
/ 01 декабря 2009

Мне нравится использовать StringBuilder с Aggregate().«Хитрость» в том, что Append() возвращает сам экземпляр StringBuilder:

var sb = arr.Aggregate( new StringBuilder(), ( s, i ) => s.Append( i ) );
var result = sb.ToString();     
5 голосов
/ 01 декабря 2009

Вы можете сделать:

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

Это дает вам ваши результаты.

1 голос
/ 02 декабря 2009

Самый эффективный способ - не преобразовывать каждое int в строку, а создать одну строку из массива символовТогда у сборщика мусора будет только один новый временный объект, о котором стоит беспокоиться.

1 голос
/ 01 декабря 2009
string.Join("", (from i in arr select i.ToString()).ToArray())

В .NET 4.0 string.Join может использовать IEnumerable<string> напрямую:

string.Join("", from i in arr select i.ToString())
1 голос
/ 01 декабря 2009

Я оставил это здесь для потомков, но не рекомендую его использовать, так как он не очень хорошо читается. Это особенно верно сейчас, когда я вернулся, чтобы узнать, через какое-то время, и мне стало интересно, о чем я думал, когда писал это (вероятно, я думал: «Дерьмо, я должен написать это, прежде чем кто-то другой отправит ответ»). .)

string s = string.Concat(arr.Cast<object>().ToArray());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...