У меня есть массив целых чисел:
int[] number = new int[] { 2,3,6,7 };
Как проще всего преобразовать их в одну строку, где числа разделяются символом (например: "2,3,6,7"
)?
Я нахожусь в С# и .NET 3.5.
У меня есть массив целых чисел:
int[] number = new int[] { 2,3,6,7 };
Как проще всего преобразовать их в одну строку, где числа разделяются символом (например: "2,3,6,7"
)?
Я нахожусь в С# и .NET 3.5.
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"
РЕДАКТИРОВАТЬ: Начиная (по крайней мере).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]);
}
}
Мне лень сравнивать эффективность предложенных методов. Но что-то говорит мне, что Join победит :)
Хотя OP, указанный .NET 3.5, люди, желающие сделать это в .NET 2.0 с С# 2, могут сделать это:
string.Join(",", Array.ConvertAll<int, String>(ints, Convert.ToString));
Я обнаружил, что существует ряд других случаев, когда использование функций Convert.xxx является более простой альтернативой лямбда, хотя в С# 3 лямбда может помочь в определении типа.
Довольно компактная версия С# 3, которая работает с .NET 2.0, такова:
string.Join(",", Array.ConvertAll(ints, item => item.ToString()))
Одна из двух подходов заключалась бы в написании метода расширения на 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"), ","));
}
}
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 показывает, что он просто добавляет значение. 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
EDIT: Это работает только в .NET 4.0+, я пропустил требование .NET 3.5 в первый раз, когда прочитал вопрос.
Я согласен с выражением лямбда для удобочитаемости и ремонтопригодности, но это не всегда будет лучшим вариантом. Недостатком использования подходов 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.Aggregate("", ( str, n ) => str +","+ n ).Substring(1);
Я также подумал, что есть более простой способ. Не знаете о производительности, у кого есть какая-то (теоретическая) идея?
В .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.ToString(",")
ints.ToString("|")
ints.ToString(":")
Отъезд
Разделитель с разделителями ToString для массива, списка, словаря, общего IEnumerable