Как присоединить int [] к символьно-разделенной строке в .NET? - PullRequest
95 голосов
/ 28 сентября 2008

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

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

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

Я в C # и .NET 3.5.

Ответы [ 10 ]

155 голосов
/ 28 сентября 2008
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"

EDIT

Я вижу несколько решений, рекламирующих использование 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 победит :)

32 голосов
/ 22 октября 2008

Хотя в 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()))
11 голосов
/ 28 сентября 2008

Одним из сочетаний двух подходов будет написание метода расширения для 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"), ","));
    }
}
8 голосов
/ 28 сентября 2008
String.Join(";", number.Select(item => item.ToString()).ToArray());

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

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

5 голосов
/ 29 ноября 2011

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

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

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 в первый раз, когда я прочитал вопрос.

5 голосов
/ 28 сентября 2008

Если ваш массив целых чисел может быть большим, вы получите лучшую производительность, используя 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: Когда я опубликовал это, у меня было ошибочное впечатление, что «StringBuilder.Append (int value)» внутренне удалось добавить строковое представление целочисленного значения без создания строкового объекта. Это неправильно: проверка метода с помощью Reflector показывает, что он просто добавляет value.ToString ().

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

2 голосов
/ 13 августа 2015

В .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 {}
}
2 голосов
/ 04 февраля 2010
ints.Aggregate("", ( str, n ) => str +","+ n ).Substring(1);

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

2 голосов
/ 28 сентября 2008

Я согласен с лямбда-выражением для удобочитаемости и удобства обслуживания, но это не всегда будет лучшим вариантом. Недостатком использования обоих подходов 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);
1 голос
/ 22 октября 2008
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...