.NET'te karakterle ayrılmış bir dizeye int [] nasıl katılır?


101

Bir dizi tam sayıya sahibim:

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

Bunları sayıların bir karakterle ayrıldığı tek bir dizeye dönüştürmenin en kolay yolu nedir (örneğin:) "2,3,6,7"?

C # ve .NET 3.5 içindeyim.


3
SO kayalar! Bu 3 mükemmel yanıtı bir Pazar günü 10 dakika içinde aldım!
Riri

4
İtibariyle .NET 4.0nesneler dizisi ve bir IEnumerable sadece bunu yapabilirsiniz almak yöntem vardır string.join(",", number). Sorunun .NET 3.5'i belirttiğini biliyorum, bu yüzden bunu bir yanıt yapmadım, ancak bir sürüm belirtmeyen aramalarda ortaya çıkıyor ve 4.0'da mümkün olduğunu bilmek birisine yardımcı olabilir.
Jason Goemaat

Yanıtlar:


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"

DÜZENLEME : (en azından) .NET 4.5 itibariyle,

var result = string.Join(",", ints.Select(x => x.ToString()).ToArray());

eşdeğerdir:

var result = string.Join(",", ints);

DÜZENLE :

Birkaç çözümün StringBuilder kullanımının reklamını yaptığını görüyorum. Birisi Join yönteminin bir IEnumerable bağımsız değişkeni alması gerektiğinden şikayet ediyor.

Seni hayal kırıklığına uğratacağım :) String.Join tek bir nedenden dolayı dizi gerektirir - performans. Birleştirme yönteminin, gerekli bellek miktarını etkin bir şekilde önceden tahsis etmek için verilerin boyutunu bilmesi gerekir.

String.Join yönteminin dahili uygulamasının bir parçası:

// 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]);
    }
}

Önerilen yöntemlerin performansını karşılaştırmak için çok tembelim. Ama bir şey bana Join'in kazanacağını söylüyor :)


Bu muhtemelen çekirdek .NET genişletme yöntemlerini kullanan en iyi bahis, ama ben gerçekten string.Join () 'i ToArray () dönüşümünden kaçınmak için bir IEnumerable <string> kabul ederdi.
spoulson

Hiçbir şey birisinin dizeyi aşırı yüklemesini engellemiyor. IEnumerable almak için de katılın. ;)
Robert P

1
Bu muhtemelen en kolay çözümdür ve sadece en hızlısı değil.
Dave Van den Eynde

9
.NET 4, parametre olarak IEnumerable'ı kabul eden bir String.Join aşırı yüklemesi sağlar. msdn.microsoft.com/en-us/library/dd783876.aspx
Ryan Kohn

using System.Linq;gerekli.
Gayan Weerakutti

32

OP, .NET 3.5'i belirtmesine rağmen, bunu C # 2 ile .NET 2.0'da yapmak isteyen kişiler bunu yapabilir:

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

Convert.xxx işlevlerinin kullanımının lambda'ya daha iyi bir alternatif olduğu bir dizi başka durum olduğunu buldum, ancak C # 3'te lambda tür çıkarımına yardımcı olabilir.

NET 2.0 ile çalışan oldukça kompakt bir C # 3 sürümü şudur:

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

11

İki yaklaşımın bir karışımı, StringBuilder kullanan IEnumerable <T> üzerine bir uzantı yöntemi yazmak olacaktır. Dönüşümü belirtmek isteyip istemediğinize veya yalnızca düz ToString'e güvenip güvenmediğinize bağlı olarak farklı aşırı yüklemelere sahip bir örnek aşağıda verilmiştir. Diğer Join türüyle karışıklığı önlemek için "Join" yerine "JoinStrings" yöntemini adlandırdım. Belki birisi daha iyi bir isim bulabilir :)

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

Güzel çözüm! Yine de projeksiyon parametresine ihtiyacınız yok, sadece x.Select (i => i.ToString ("X")) yazabilirsiniz. JoinStrings (";") daha deyimseldir.
JacquesB

Evet, daha sonra bunu düşündüm. Bazen hepsini tek seferde belirleyebilmek güzel, ancak işlemleri bölmek kesinlikle daha zarif :)
Jon Skeet

8
String.Join(";", number.Select(item => item.ToString()).ToArray());

Birleştirmeden Stringönce öğelerin her birini a'ya dönüştürmeliyiz , bu yüzden kullanmak mantıklı Selectve bir lambda ifadesi. Bu, mapdiğer bazı dillerdeki ile eşdeğerdir . Daha sonra, sonuçta ortaya çıkan dizge koleksiyonunu bir diziye dönüştürmemiz gerekir, çünkü String.Joinyalnızca bir dizge dizisini kabul eder.

ToArray()Bence biraz çirkin. String.Joingerçekten kabul etmelisiniz IEnumerable<String>, onu yalnızca dizilerle sınırlamak için hiçbir neden yoktur. Bunun nedeni büyük olasılıkla Join, dizilerin mevcut olan tek tür koleksiyon türü olduğu zaman jeneriklerden önce gelmesidir.


5

Tamsayı diziniz büyükse, bir StringBuilder kullanarak daha iyi performans elde edersiniz. Örneğin:

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

Düzenleme: Bunu yayınladığımda, "StringBuilder.Append (int value)" ifadesinin dahili olarak bir dize nesnesi oluşturmadan tamsayı değerinin dize temsilini eklemeyi başardığı yanlış izlenimi altındaydım. Bu yanlış: Yöntemi Reflector ile incelemek, basitçe value.ToString () eklediğini gösterir.

Bu nedenle, tek potansiyel performans farkı, bu tekniğin bir dizi oluşturmadan kaçınması ve dizeleri çöp toplama için biraz daha erken serbest bırakmasıdır. Pratikte bu ölçülebilir bir fark yaratmayacak, bu yüzden bu daha iyi çözüme oy verdim .


Daha hızlı olmasını mı ölçtün? String.Join ayrıca bir StringBuilder kullanır.
JacquesB

Evet, ama önce her şeyi bir diziye dönüştürmen gerekiyor ki bu ideal olmaktan çok uzak. Özellikle, sonuçta ortaya çıkan dizgeyi oluşturmaya başlamadan önce , dönüştürülen tüm dizeleri bellekte aynı anda bulundurmanız gerektiği anlamına gelir .
Jon Skeet

OTOH String.Join, StringBuilder arabelleğinin boyutunu önceden hesaplar, böylece yeniden boyutlandırmayı önler. Bu nedenle, daha fazla bellek gerektirse bile daha hızlı olabilir.
JacquesB

5

Soru, "bunları sayının bir karakterle ayrıldığı tek bir dizeye dönüştürmenin en kolay yolu" içindir.

En kolay yol şudur:

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

DÜZENLEME: Bu yalnızca .NET 4.0+ ile çalışır, soruyu ilk okuduğumda .NET 3.5 gereksinimini kaçırdım.


Bu string olarak geçerli değildir.Join metodu yalnızca bir dizi dizge alır. Bir göz atın msdn.microsoft.com/en-us/library/tk0xe5h0.aspx
ppolyzos

1
Aşırı yüklenmiş bir yöntem: msdn.microsoft.com/en-us/library/dd988350 Yeni bir konsol uygulamasına yazdığım kodu kopyaladım, bir Console.WriteLine ekledim ve çıktı: 2,3,6,7
WebMasterP

1
Bunun yalnızca .net 4'te mevcut olduğunu düşünüyorum
Govind Malviya

Bir int dizisi değil, bir nesne dizisi (veya dize dizisi) gerektirir. Bir "çağrı belirsiz" hatası verir.
LarryBud

2

Okunabilirlik ve sürdürülebilirlik için lambda ifadesine katılıyorum, ancak bu her zaman en iyi seçenek olmayacak. Hem IEnumerable / ToArray hem de StringBuilder yaklaşımlarını kullanmanın dezavantajı, son dize için ne kadar alana ihtiyaç duyulacağını bilmediklerinden, öğelerden veya karakterlerden oluşan bir listeyi dinamik olarak büyütmek zorunda olmalarıdır.

Hızın özlü olmaktan daha önemli olduğu nadir bir durumsa, aşağıdaki daha etkilidir.

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

Daha basit bir yol olduğunu da düşündüm. Performansı bilmiyorum, herhangi bir (teorik) fikri olan var mı?


Bu çözüm size "1,2,3,4,5" verir.
Sarin

Teşekkürler, bunu Substring(1)düzeltmek için ekledim (bellekten geliyordu).
geçersiz

2

.NET 4.0'da, dize birleştirmenin bir aşırı yüklemesi vardır params object[], bu nedenle şu kadar basittir:

int[] ids = new int[] { 1, 2, 3 };
string.Join(",", ids);

misal

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'da böyle bir aşırı yükleme olmadığı için biraz daha zordur. Yani kendi genel yönteminize ihtiyacınız var:

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'te, uzantı yöntemlerini kullanabilirsiniz:

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

}

Böylece JoinArray uzantı yöntemini kullanabilirsiniz.

int[] ids = new int[] { 1, 2, 3 };
string strIdList = ids.JoinArray(",");

ExtensionAttribute'u kodunuza eklerseniz, bu uzantı yöntemini .NET 2.0'da da kullanabilirsiniz:

// 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 {}
}


0

.net 3.5'i unutun ve .net çekirdeğindeki sonraki kodu kullanın

var result = string.Join(",", ints);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.