Как присоединить int[] к символьно-разделенной строке в.NET?

У меня есть массив целых чисел:

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

Какой самый простой способ преобразовать их в одну строку, где числа разделены символом (например: "2,3,6,7")?

Я в C# и.NET 3.5.

10 ответов

Решение
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"

РЕДАКТИРОВАТЬ:

Я вижу, что несколько решений рекламируют использование StringBuilder. Кто-то жалуется, что метод Join должен принимать аргумент IEnumerable.

Я вас разочарую:) String.Join требует массив по одной причине - производительность. Метод соединения должен знать размер данных, чтобы эффективно распределить необходимый объем памяти.

Вот часть внутренней реализации метода String.Join:

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

Мне лень сравнивать эффективность предложенных методов. Но что-то подсказывает мне, что Join победит:)

Хотя в OP указан.NET 3.5, люди, желающие сделать это в.NET 2.0 с C#2, могут сделать это:

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

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

Довольно компактная версия C#3, которая работает с.NET 2.0, такова:

string.Join(",", Array.ConvertAll(ints, item => item.ToString()))

Одним из сочетаний двух подходов было бы написать метод расширения для IEnumerable, в котором использовался StringBuilder. Вот пример с различными перегрузками в зависимости от того, хотите ли вы указать преобразование или просто полагаться на простую ToString. Я назвал метод "JoinStrings" вместо "Join", чтобы избежать путаницы с другим типом Join. Возможно, кто-то может придумать лучшее имя:)

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"), ","));
    }
}
String.Join(";", number.Select(item => item.ToString()).ToArray());

Мы должны преобразовать каждый из пунктов в String прежде чем мы сможем присоединиться к ним, так что имеет смысл использовать Select и лямбда-выражение. Это эквивалентно map на некоторых других языках. Затем мы должны преобразовать полученную коллекцию строк обратно в массив, потому что String.Join принимает только строковый массив.

ToArray() это немного некрасиво, я думаю. String.Join должен действительно принять IEnumerable<String>, нет причин ограничивать его только массивами. Это, вероятно, только потому, что Join до появления дженериков, когда массивы были единственным доступным типом коллекции.

Если ваш массив целых чисел может быть большим, вы получите лучшую производительность, используя StringBuilder. Например:

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

Изменить: Когда я опубликовал это, у меня было ошибочное впечатление, что "StringBuilder.Append(int value)" внутренне удалось добавить строковое представление целочисленного значения без создания строкового объекта. Это неправильно: проверка метода с помощью Reflector показывает, что он просто добавляет value.ToString().

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

Вопрос заключается в том, чтобы "проще всего преобразовать их в одну строку, где числа разделены символом".

Самый простой способ это:

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

РЕДАКТИРОВАТЬ: Это работает только в.NET 4.0+, я пропустил требование.NET 3.5 в первый раз, когда я прочитал вопрос.

В.NET 4.0 объединение строк имеет перегрузку для params object[]так же просто, как:

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

пример

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

В.NET 2.0 это немного сложнее, поскольку такой перегрузки нет. Итак, вам нужен ваш собственный общий метод:

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

В.NET 3.5 вы можете использовать методы расширения:

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

}

Таким образом, вы можете использовать метод расширения JoinArray.

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

Вы также можете использовать этот метод расширения в.NET 2.0, если добавите ExtensionAttribute в свой код:

// 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 {}
}
ints.Aggregate("", ( str, n ) => str +","+ n ).Substring(1);

Я также думал, что есть более простой способ. Не знаете о производительности, у кого-нибудь есть (теоретическая) идея?

Я согласен с лямбда-выражением для удобочитаемости и удобства обслуживания, но это не всегда будет лучшим вариантом. Недостатком использования обоих подходов IEnumerable/ToArray и StringBuilder является то, что они должны динамически увеличивать список, состоящий из элементов или символов, поскольку они не знают, сколько места потребуется для окончательной строки.

Если редкий случай, когда скорость важнее, чем краткость, следующее более эффективно.

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

Ты можешь сделать

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

Проверять, выписываться

Разделитель с разделителями ToString для массива, списка, словаря, универсального IEnumerable

Forget about .net 3.5 and use next code in .net core

var result = string.Join(",", ints);
Другие вопросы по тегам