【问题标题】:int array to stringint 数组到字符串
【发布时间】:2009-11-30 22:20:22
【问题描述】:

在 C# 中,我有一个整数数组,仅包含数字。我想把这个数组转换成字符串。

数组示例:

int[] arr = {0,1,2,3,0,1};

如何将其转换为格式为:"012301" 的字符串?

【问题讨论】:

    标签: c# arrays string


    【解决方案1】:

    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);
    

    【讨论】:

    【解决方案2】:

    您可以简单地使用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});
    

    【讨论】:

    • 此解决方案适用于 .NET 4.0 及更高版本
    【解决方案3】:

    我意识到我的意见可能不是流行的,但我想我很难跳上 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');
    

    【讨论】:

    • 你让我知道你创建了一个字符串数组并填充它,这样你就可以调用 string.join。当您可以利用延迟执行并完全跳过字符串数组时,这是一种资源浪费。 Join 中的代码不是火箭科学,编写通用的“Join”或“Delimit”方法(如果必须的话,可以使用扩展方法)是一个简单的练习,它遍历枚举器并构建分隔字符串。我明白了一般观点并同意,但由于示例代码愚蠢,我无法投票。对不起老兄
    • P.S.您可以使用 LINQ 并获得延迟执行的强大功能,而无需将其全部塞进一行。我同意那里有太多塞满的 LINQy 示例。它让我想起了在学习 C 的那一天,人们会编写一行 WTF 代码来复制字符串“while(*dst++ = *src++);”。不是因为它更好/更快/更具可读性(绝对不是最后一个),而是因为它们可以并且这让他们(好吧,我也是)感觉很聪明。当然,它应该写得更清楚,不管它让你感觉多么聪明或不聪明。对不起,在伙伴身上跑步。
    • 感谢您的反馈。我不会声称自己是这方面的专家。但是,我确实测试了以下代码行,它的执行速度明显慢于使用数组的实现: res = arr.Aggregate(string.Empty, (s, i) => s + i.ToString());对于连接长度为 100 的 int[] 的 100 万次迭代,这需要大约 60 秒,而使用数组则需要 40 秒。这对我来说似乎效率低下,因为我假设它在每次迭代时都会进行连接,而 string.Join 只进行一次连接。如果我缺少更有效的方法,请告诉我。
    • 顺便说一句,我相信只有在使用返回一组结果的函数(例如 Intersect)时才能利用延迟执行,但如果您使用的函数返回单个结果(如聚合),然后代码将立即在所有元素上执行。在这种情况下,由于我们试图返回单个字符串值,我认为不能应用延迟执行。
    • 感谢 cmets,几点:1) 如果性能是一个真正的问题,甚至谈论我的解决方案也没有意义,但在大多数工作的 90% 中,性能可能不是问题。我从常见的情况开始。 2) 通常我习惯性地返回空集合而不是 null 以减少混乱,这正是您在早期示例中说明的原因。 3)您对(缺乏)延期执行是正确的。 4)我认为这只是品味问题。对于从 C++ 转向 C# 的人来说,您的最终解决方案可能更清楚;我更喜欢物理上更简洁、更实用的方法。
    【解决方案4】:

    为避免创建额外的数组,您可以执行以下操作。

    var builder = new StringBuilder();
    Array.ForEach(arr, x => builder.Append(x));
    var res = builder.ToString();
    

    【讨论】:

    • 尚未对此进行验证,但您可能可以传递 builder.Append 而不是 lambda 表达式,因为 builder.AppendArray.ForEach 中预期委托的签名匹配。
    • Steve,好主意,但这行不通,因为ForEach() 期望void,而Append() 返回StringBuilder
    【解决方案5】:
    string result = arr.Aggregate("", (s, i) => s + i.ToString());
    

    (免责声明:如果您有很多位数(至少数百位)并且您关心性能,我建议您避免使用这种方法并使用 StringBuilder,如 JaredPar 的回答。)

    【讨论】:

    • 这实际上是看似昂贵的。这具有“伸缩”内存要求,因此对于小型阵列上的任何内容都不理想。对不起。
    • 这对于小型数组来说很好,但它在每次迭代时都构建一个字符串这一事实对于较大的数组或该代码被大量调用的地方来说是一个问题。
    • 这是绝对正确的,如果性能是一个问题,那么你不应该这样做。但是,如果只有少数数字,我会为了清晰和简洁而写下这个(尽管我确信口味可能会有所不同。)
    • 是的,Aggregate() 是对的,但你应该使用 StringBuilder。看我的回答。
    【解决方案6】:

    你可以这样做:

     int[] arr = {0,1,2,3,0,1};
     string results = string.Join("",arr.Select(i => i.ToString()).ToArray());
    

    这会给你结果。

    【讨论】:

      【解决方案7】:

      我喜欢将StringBuilderAggregate() 一起使用。 “诀窍”是 Append() 返回 StringBuilder 实例本身:

      var sb = arr.Aggregate( new StringBuilder(), ( s, i ) => s.Append( i ) );
      var result = sb.ToString();     
      

      【讨论】:

        【解决方案8】:
        string.Join("", (from i in arr select i.ToString()).ToArray())
        

        在 .NET 4.0 中,string.Join 可以直接使用IEnumerable&lt;string&gt;

        string.Join("", from i in arr select i.ToString())
        

        【讨论】:

          【解决方案9】:

          我把它留在这里以供后代使用,但不推荐使用它,因为它的可读性不是很好。现在尤其如此,因为一段时间后我回来看看是否想知道我在写它时在想什么(我可能在想'废话,必须在其他人发布答案之前把它写下来' .)

          string s = string.Concat(arr.Cast<object>().ToArray());
          

          【讨论】:

          • +1。如果您不需要任何分隔符,这是最简单的方法,这是 OP 要求的。当然没有重载来支持分隔符...
          • (我认为在这种形式下,它会被一个简单的 StringBuilder 解决方案严重超越。)
          【解决方案10】:

          最有效的方法不是将每个 int 转换为字符串,而是从一个字符数组中创建一个字符串。那么垃圾收集器只需要担心一个新的临时对象。

          int[] arr = {0,1,2,3,0,1};
          string result = new string(Array.ConvertAll<int,char>(arr, x => Convert.ToChar(x + '0')));
          

          【讨论】:

            【解决方案11】:

            这是一种迂回的方式,代码不多,初学者容易理解

                int[] arr = {0,1,2,3,0,1};
                string joined = "";
                foreach(int i in arr){
                    joined += i.ToString();
                }
                int number = int.Parse(joined);
                
            

            【讨论】:

              【解决方案12】:

              如果这是一个长数组,你可以使用

              var sb = arr.Aggregate(new StringBuilder(), ( s, i ) => s.Append( i ), s.ToString());
              

              【讨论】:

                【解决方案13】:
                // 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);
                

                【讨论】:

                • 只有代码的答案没那么有用。请解释你的代码
                猜你喜欢
                • 1970-01-01
                • 2018-05-03
                • 1970-01-01
                • 2016-06-11
                • 1970-01-01
                • 2020-09-02
                • 1970-01-01
                • 2014-05-01
                • 1970-01-01
                相关资源
                最近更新 更多