web-dev-qa-db-ja.com

int []を.NETの文字区切り文字列に結合する方法は?

私は整数の配列を持っています:

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

これらを数字で区切られた単一の文字列に変換する最も簡単な方法は何ですか(たとえば:"2,3,6,7")?

私はC#と.NET 3.5を使用しています。

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

[〜#〜] edit [〜#〜]

StringBuilderの使用法を宣伝するソリューションがいくつかあります。 JoinメソッドがIEnumerable引数を取る必要があるという苦情。

私はあなたを失望させます:) String.Joinは単一の理由で配列を必要とします-パフォーマンス。 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が勝つことを教えてくれます:)

159
aku

OPは.NET 3.5を指定しましたが、C#2を使用して.NET 2.0でこれを実行したい人はこれを実行できます。

string.Join(",", Array.ConvertAll<int, String>(ints, Convert.ToString));

Convert.xxx関数の使用がラムダに代わるきれいな代替である他の多くのケースがありますが、C#3ではラムダが型推論を助けるかもしれません。

.NET 2.0で動作するかなりコンパクトなC#3バージョンは次のとおりです。

string.Join(",", Array.ConvertAll(ints, item => item.ToString()))
32
Will Dean

2つのアプローチの1つの混合は、StringBuilderを使用するIEnumerable <T>に拡張メソッドを記述することです。次に例を示します。変換を指定するか、単純なToStringに依存するかによって、オーバーロードが異なります。他の種類のJoinとの混同を避けるために、メソッドに「Join」ではなく「JoinStrings」という名前を付けました。おそらく誰かがより良い名前を思いつくことができます:)

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"), ","));
    }
}
11
Jon Skeet
_String.Join(";", number.Select(item => item.ToString()).ToArray());
_

各項目を結合する前にStringに変換する必要があるため、Selectとラムダ式を使用することは理にかなっています。これは、他の言語のmapと同等です。 _String.Join_は文字列配列のみを受け入れるため、結果の文字列のコレクションを変換して配列に戻す必要があります。

ToArray()は少しslightlyいと思います。 _String.Join_は実際に_IEnumerable<String>_を受け入れる必要があります。配列のみに制限する理由はありません。これはおそらく、Joinがジェネリックの前にあるためであり、配列が利用可能な型付きコレクションの唯一の種類であったためです。

8
JacquesB

整数の配列が大きい場合、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()が単に追加されていることがわかります。

したがって、唯一の潜在的なパフォーマンスの違いは、この手法が1つの配列の作成を回避し、ガベージコレクション用の文字列を少し早く解放することです。実際には、これは測定可能な違いをもたらさないので、私は このより良い解決策 を支持しました。

5
Joe

問題は、「これらを数字で区切られた単一の文字列に変換する最も簡単な方法」です。

最も簡単な方法は次のとおりです。

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

編集:これは.NET 4.0+でのみ機能し、質問を初めて読んだときに.NET 3.5の要件を逃しました。

5
WebMasterP

.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(",");

コードにExtensionAttributeを追加する場合、.NET 2.0でその拡張メソッドを使用することもできます。

// 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 {}
}
2
Stefan Steiger

可読性と保守性についてはラムダ式に同意しますが、常に最良の選択肢とは限りません。 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
DocMax
ints.Aggregate("", ( str, n ) => str +","+ n ).Substring(1);

また、もっと簡単な方法があると思いました。パフォーマンスについて知らない、誰もが(理論的な)アイデアを持っていますか?

2
void

できるよ

ints.ToString(",")
ints.ToString("|")
ints.ToString(":")

チェックアウト

配列、リスト、辞書、汎用IEnumerableの区切り文字区切りのToString

1
Ray Lu