Як приєднати 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.