Як приєднати int [] до рядка, розділеного символами .NET?


101

У мене є масив цілих чисел:

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

Який найпростіший спосіб перетворити їх у єдиний рядок, де числа розділені символом (наприклад "2,3,6,7":)?

Я в C # і .NET 3.5.


3
ТАК скелі! Я отримав ці 3 чудові відповіді протягом 10 хвилин у неділю!
Рірі

4
На .NET 4.0сьогоднішній день існують методи, які беруть масив об'єктів та IEnumerable, щоб ви могли просто зробити string.join(",", number). Я знаю, що питання вказує на .NET 3.5, тому я не став на це відповідь, але він з'являється в пошуках, які не визначають версію, і знаючи, що це можливо в 4.0, може допомогти комусь.
Джейсон Джейм

Відповіді:


162
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 : Станом на (принаймні) .NET 4.5,

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

еквівалентно:

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

Редагувати :

Я бачу, що кілька рішень рекламують використання 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]);
    }
}

Я лінуюся порівнювати ефективність запропонованих методів. Але щось підказує мені, що Приєднуйся переможеш :)


Це, мабуть, найкраща ставка з використанням основних методів розширення .NET, але я дуже хотів, щоб string.Join () прийняв IEnumerable <string>, щоб уникнути перетворення ToArray ().
Spoulson

Ніщо не заважає комусь перевантажувати рядок. Приєднуйтесь і до IEnumerable. ;)
Роберт П

1
Це, мабуть, також найпростіше рішення, причому не просто найшвидше.
Дейв Ван ден Ейнде

9
.NET 4 забезпечує перевантаження String.Join, яка приймає IEnumerable як параметр. msdn.microsoft.com/en-us/library/dd783876.aspx
Ryan Kohn

using System.Linq;необхідно.
Гаян Веракутті

32

Хоча 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

Однією із сумішей двох підходів було б написати метод розширення на IEnumerable <T>, який використовував 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"), ","));
    }
}

Приємне рішення! Вам не потрібен параметр проекції, ви можете просто написати x.Select (i => i.ToString ("X")). JoinStrings (";"), який є більш ідіоматичним.
ЖакБ

Так, я подумав про це згодом. Іноді приємно мати змогу вказати все за один раз, але, безумовно, більш елегантно розділити операції :)
Джон Скіт,

8
String.Join(";", number.Select(item => item.ToString()).ToArray());

Ми повинні перетворити кожен із елементів у формат, Stringперш ніж ми зможемо приєднатись до них, тому має сенс використовувати Selectі лямбда-вираз. Це еквівалентно mapв деяких інших мовах. Тоді ми маємо перетворити отриману колекцію рядка назад у масив, оскільки String.Joinприймає лише рядковий масив.

ToArray()Трохи негарно , я думаю. String.JoinСправді слід прийняти IEnumerable<String>, немає причин обмежувати його лише масивами. Це, мабуть, тільки тому, що Joinце було раніше, ніж дженерики, коли масиви були єдиним видом набраних колекцій.


5

Якщо ваш масив цілих чисел може бути великим, ви отримаєте кращу продуктивність за допомогою 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 ().

Тому єдиною різницею потенційних можливостей є те, що ця методика дозволяє уникнути створення одного масиву і трохи швидше звільнить рядки для збору сміття. На практиці це не може змінити жодної міри, тому я підтримав це краще рішення .


Ви виміряли це, щоб було швидше? String.Join також використовує StringBuilder.
ЖакB

Так, але спочатку потрібно перетворити всю річ у масив, що далеко не ідеально. Зокрема, це означає, що вам потрібно мати всі перетворені рядки в пам’яті одночасно, перш ніж почати створювати отриманий рядок.
Джон Скіт

OTOH String.Join попередньо розраховує розмір буфера StringBuilder, щоб уникнути зміни розміру. Тож це може бути швидше, навіть якщо для цього потрібно більше пам’яті.
ЖакБ

5

Питання полягає в "найпростішому способі їх перетворення в один рядок, де число розділено символом".

Найпростіший спосіб:

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

EDIT: Це працює лише у .NET 4.0+, я пропустив вимогу .NET 3.5 під час першого прочитання питання.


Це не вірно, оскільки string.Join метод бере лише масив рядків. Подивіться тут msdn.microsoft.com/en-us/library/tk0xe5h0.aspx
ppolyzos

1
Це перевантажений метод: msdn.microsoft.com/en-us/library/dd988350 Я просто скопіював код, який я записав, у нову консольну програму, додав Console.WriteLine, і це результат: 2,3,6,7
WebMasterP

1
Я думаю, що це доступно лише у .net 4
Говінд Мальвія

Потрібен масив об'єктів (або рядковий масив), а не int масив. Подасть помилку «дзвінок неоднозначно».
LarryBud

2

Я погоджуюся з виразом лямбда щодо читабельності та ремонтопридатності, але це не завжди буде найкращим варіантом. Недоліком використання як підходів 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);

2
ints.Aggregate("", ( str, n ) => str +","+ n ).Substring(1);

Я також думав, що існує простіший спосіб. Не знаєте про продуктивність, хтось має якусь (теоретичну) ідею?


Це рішення дасть вам ", 1,2,3,4,5".
Сарін

Дякую, я додав, Substring(1)щоб це виправити (це було з пам'яті).
недійсна

2

У .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 {}
}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.