【发布时间】:2009-11-30 22:20:22
【问题描述】:
在 C# 中,我有一个整数数组,仅包含数字。我想把这个数组转换成字符串。
数组示例:
int[] arr = {0,1,2,3,0,1};
如何将其转换为格式为:"012301" 的字符串?
【问题讨论】:
在 C# 中,我有一个整数数组,仅包含数字。我想把这个数组转换成字符串。
数组示例:
int[] arr = {0,1,2,3,0,1};
如何将其转换为格式为:"012301" 的字符串?
【问题讨论】:
at.net 3.5 使用:
String.Join("", new List<int>(array).ConvertAll(i => i.ToString()).ToArray());
at.net 4.0 或更高版本使用:(见@Jan Remunda 的回答)
string result = string.Join("", array);
【讨论】:
您可以简单地使用String.Join 函数,并使用string.Empty 作为分隔符,因为它在内部使用StringBuilder。
string result = string.Join(string.Empty, new []{0,1,2,3,0,1});
例如:如果您使用分号作为分隔符,结果将是0;1;2;3;0;1。
它实际上与空分隔符一起使用,第二个参数可以是任何对象的枚举,例如:
string result = string.Join(null, new object[]{0,1,2,3,0,"A",DateTime.Now});
【讨论】:
我意识到我的意见可能不是流行的,但我想我很难跳上 Linq-y 乐队的马车。这很漂亮。它是浓缩的。我明白了,我不反对在适当的地方使用它。也许只有我一个人,但我觉得人们已经不再考虑创建实用程序函数来完成他们想要的事情,而是更喜欢用(有时)过长的 Linq 代码行来乱扔他们的代码,以便创建一个密集的 1-liner。
我并不是说人们在这里提供的任何 Linq 答案都是不好的,但我想我觉得这些单行代码有可能会开始变得更长、更模糊,因为你需要处理各种情况。如果您的数组为空怎么办?如果您想要一个分隔字符串而不是纯粹连接怎么办?如果您的数组中的某些整数是两位数,并且您想用前导零填充每个值,以便每个元素的字符串与其余元素的长度相同,该怎么办?
以提供的答案之一为例:
result = arr.Aggregate(string.Empty, (s, i) => s + i.ToString());
如果我需要担心数组为空,现在变成这样:
result = (arr == null) ? null : arr.Aggregate(string.Empty, (s, i) => s + i.ToString());
如果我想要一个逗号分隔的字符串,现在变成这样:
result = (arr == null) ? null : arr.Skip(1).Aggregate(arr[0].ToString(), (s, i) => s + "," + i.ToString());
这还不算太糟糕,但我觉得这行代码在做什么并不明显。
当然,没有什么可以阻止您将这行代码放入您自己的实用程序函数中,这样您的应用程序逻辑中就不会混入那么长的混乱,特别是如果您在多个地方执行此操作:
public static string ToStringLinqy<T>(this T[] array, string delimiter)
{
// edit: let's replace this with a "better" version using a StringBuilder
//return (array == null) ? null : (array.Length == 0) ? string.Empty : array.Skip(1).Aggregate(array[0].ToString(), (s, i) => s + "," + i.ToString());
return (array == null) ? null : (array.Length == 0) ? string.Empty : array.Skip(1).Aggregate(new StringBuilder(array[0].ToString()), (s, i) => s.Append(delimiter).Append(i), s => s.ToString());
}
但是,如果您无论如何要将其放入实用程序函数中,您真的需要将其压缩为 1-liner 吗?在这种情况下,为什么不添加一些额外的行以清楚起见并利用 StringBuilder 以便您不进行重复的连接操作:
public static string ToStringNonLinqy<T>(this T[] array, string delimiter)
{
if (array != null)
{
// edit: replaced my previous implementation to use StringBuilder
if (array.Length > 0)
{
StringBuilder builder = new StringBuilder();
builder.Append(array[0]);
for (int i = 1; i < array.Length; i++)
{
builder.Append(delimiter);
builder.Append(array[i]);
}
return builder.ToString()
}
else
{
return string.Empty;
}
}
else
{
return null;
}
}
如果你真的很关心性能,你甚至可以把它变成一个混合函数,根据数组中有多少元素来决定是执行 string.Join 还是使用 StringBuilder(这是一个微-优化,在我看来不值得做,而且可能弊大于利,但我用它作为这个问题的例子):
public static string ToString<T>(this T[] array, string delimiter)
{
if (array != null)
{
// determine if the length of the array is greater than the performance threshold for using a stringbuilder
// 10 is just an arbitrary threshold value I've chosen
if (array.Length < 10)
{
// assumption is that for arrays of less than 10 elements
// this code would be more efficient than a StringBuilder.
// Note: this is a crazy/pointless micro-optimization. Don't do this.
string[] values = new string[array.Length];
for (int i = 0; i < values.Length; i++)
values[i] = array[i].ToString();
return string.Join(delimiter, values);
}
else
{
// for arrays of length 10 or longer, use a StringBuilder
StringBuilder sb = new StringBuilder();
sb.Append(array[0]);
for (int i = 1; i < array.Length; i++)
{
sb.Append(delimiter);
sb.Append(array[i]);
}
return sb.ToString();
}
}
else
{
return null;
}
}
对于此示例,性能影响可能不值得关心,但重点是,如果您确实需要关注操作的性能,无论它们是什么,那么它都会在实用程序函数中处理它很可能比使用复杂的 Linq 表达式更容易和更易读。
那个实用函数看起来还是有点笨重。现在让我们抛弃混合的东西并这样做:
// convert an enumeration of one type into an enumeration of another type
public static IEnumerable<TOut> Convert<TIn, TOut>(this IEnumerable<TIn> input, Func<TIn, TOut> conversion)
{
foreach (TIn value in input)
{
yield return conversion(value);
}
}
// concatenate the strings in an enumeration separated by the specified delimiter
public static string Delimit<T>(this IEnumerable<T> input, string delimiter)
{
IEnumerator<T> enumerator = input.GetEnumerator();
if (enumerator.MoveNext())
{
StringBuilder builder = new StringBuilder();
// start off with the first element
builder.Append(enumerator.Current);
// append the remaining elements separated by the delimiter
while (enumerator.MoveNext())
{
builder.Append(delimiter);
builder.Append(enumerator.Current);
}
return builder.ToString();
}
else
{
return string.Empty;
}
}
// concatenate all elements
public static string ToString<T>(this IEnumerable<T> input)
{
return ToString(input, string.Empty);
}
// concatenate all elements separated by a delimiter
public static string ToString<T>(this IEnumerable<T> input, string delimiter)
{
return input.Delimit(delimiter);
}
// concatenate all elements, each one left-padded to a minimum length
public static string ToString<T>(this IEnumerable<T> input, int minLength, char paddingChar)
{
return input.Convert(i => i.ToString().PadLeft(minLength, paddingChar)).Delimit(string.Empty);
}
现在我们有了独立且相当紧凑的实用功能,每个功能都可以说是有用的。
最后,我的意思不是你不应该使用 Linq,而只是说不要忘记创建自己的实用程序函数的好处,即使它们很小并且可能只包含一行返回一行 Linq 代码的结果。如果不出意外,您将能够使您的应用程序代码比使用一行 Linq 代码所能实现的更简洁,并且如果您在多个地方使用它,那么使用实用程序函数可以更轻松地调整您的输出以防您以后需要更改它。
对于这个问题,我宁愿在我的应用程序代码中写这样的东西:
int[] arr = { 0, 1, 2, 3, 0, 1 };
// 012301
result = arr.ToString<int>();
// comma-separated values
// 0,1,2,3,0,1
result = arr.ToString(",");
// left-padded to 2 digits
// 000102030001
result = arr.ToString(2, '0');
【讨论】:
为避免创建额外的数组,您可以执行以下操作。
var builder = new StringBuilder();
Array.ForEach(arr, x => builder.Append(x));
var res = builder.ToString();
【讨论】:
builder.Append 而不是 lambda 表达式,因为 builder.Append 与 Array.ForEach 中预期委托的签名匹配。
ForEach() 期望void,而Append() 返回StringBuilder。
string result = arr.Aggregate("", (s, i) => s + i.ToString());
(免责声明:如果您有很多位数(至少数百位)并且您关心性能,我建议您避免使用这种方法并使用 StringBuilder,如 JaredPar 的回答。)
【讨论】:
你可以这样做:
int[] arr = {0,1,2,3,0,1};
string results = string.Join("",arr.Select(i => i.ToString()).ToArray());
这会给你结果。
【讨论】:
我喜欢将StringBuilder 与Aggregate() 一起使用。 “诀窍”是 Append() 返回 StringBuilder 实例本身:
var sb = arr.Aggregate( new StringBuilder(), ( s, i ) => s.Append( i ) );
var result = sb.ToString();
【讨论】:
string.Join("", (from i in arr select i.ToString()).ToArray())
在 .NET 4.0 中,string.Join 可以直接使用IEnumerable<string>:
string.Join("", from i in arr select i.ToString())
【讨论】:
我把它留在这里以供后代使用,但不推荐使用它,因为它的可读性不是很好。现在尤其如此,因为一段时间后我回来看看是否想知道我在写它时在想什么(我可能在想'废话,必须在其他人发布答案之前把它写下来' .)
string s = string.Concat(arr.Cast<object>().ToArray());
【讨论】:
最有效的方法不是将每个 int 转换为字符串,而是从一个字符数组中创建一个字符串。那么垃圾收集器只需要担心一个新的临时对象。
int[] arr = {0,1,2,3,0,1};
string result = new string(Array.ConvertAll<int,char>(arr, x => Convert.ToChar(x + '0')));
【讨论】:
这是一种迂回的方式,代码不多,初学者容易理解
int[] arr = {0,1,2,3,0,1};
string joined = "";
foreach(int i in arr){
joined += i.ToString();
}
int number = int.Parse(joined);
【讨论】:
如果这是一个长数组,你可以使用
var sb = arr.Aggregate(new StringBuilder(), ( s, i ) => s.Append( i ), s.ToString());
【讨论】:
// This is the original array
int[] nums = {1, 2, 3};
// This is an empty string we will end up with
string numbers = "";
// iterate on every char in the array
foreach (var item in nums)
{
// add the char to the empty string
numbers += Convert.ToString(item);
}
// Write the string in the console
Console.WriteLine(numbers);
【讨论】: