Come unire int [] a una stringa separata da caratteri in .NET?


101

Ho un array di numeri interi:

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

Qual è il modo più semplice per convertirli in un'unica stringa in cui i numeri sono separati da un carattere (come:) "2,3,6,7"?

Sono in C # e .NET 3.5.


3
COSÌ rocce! Ho ricevuto queste 3 eccellenti risposte in 10 minuti di domenica!
Riri

4
Al momento .NET 4.0ci sono metodi che accettano un array di oggetti e un IEnumerable, quindi puoi semplicemente farlo string.join(",", number). So che la domanda specifica .NET 3.5, quindi non ne ho fatto una risposta, ma viene fuori in ricerche che non specificano una versione e sapere che è possibile in 4.0 potrebbe aiutare qualcuno.
Jason Goemaat,

Risposte:


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"

EDIT : a partire da (almeno) .NET 4.5,

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

è equivalente a:

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

MODIFICA :

Vedo diverse soluzioni che pubblicizzano l'utilizzo di StringBuilder. Qualcuno si lamenta che il metodo Join dovrebbe accettare un argomento IEnumerable.

Ti deluderò :) String.Join richiede array per un unico motivo: le prestazioni. Il metodo Join deve conoscere la dimensione dei dati per preallocare efficacemente la quantità di memoria necessaria.

Ecco una parte dell'implementazione interna del metodo 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]);
    }
}

Sono troppo pigro per confrontare le prestazioni dei metodi suggeriti. Ma qualcosa mi dice che Join vincerà :)


Questa è probabilmente la soluzione migliore utilizzando i metodi di estensione .NET di base, ma avrei davvero desiderato string.Join () avrebbe accettato un IEnumerable <string> per evitare la conversione ToArray ().
spoulson

Niente impedisce a qualcuno di sovraccaricare la stringa. Partecipa anche per prendere un IEnumerable. ;)
Robert P

1
Questa è probabilmente anche la soluzione più semplice e non solo la più veloce.
Dave Van den Eynde

9
.NET 4 fornisce un overload String.Join che accetta IEnumerable come parametro. msdn.microsoft.com/en-us/library/dd783876.aspx
Ryan Kohn,

using System.Linq;è obbligatorio.
Gayan Weerakutti

32

Sebbene l'OP abbia specificato .NET 3.5, le persone che desiderano farlo in .NET 2.0 con C # 2 possono farlo:

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

Trovo che ci siano una serie di altri casi in cui l'uso delle funzioni Convert.xxx è un'alternativa più ordinata a un lambda, sebbene in C # 3 il lambda potrebbe aiutare l'inferenza del tipo.

Una versione C # 3 abbastanza compatta che funziona con .NET 2.0 è questa:

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

11

Una combinazione dei due approcci sarebbe scrivere un metodo di estensione su IEnumerable <T> che utilizza StringBuilder. Ecco un esempio, con sovraccarichi diversi a seconda che si desideri specificare la trasformazione o semplicemente fare affidamento su ToString semplice. Ho chiamato il metodo "JoinStrings" invece di "Join" per evitare confusione con l'altro tipo di Join. Forse qualcuno può inventare un nome migliore :)

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

Bella soluzione! Tuttavia, non è necessario il parametro di proiezione, puoi semplicemente scrivere x.Select (i => i.ToString ("X")). JoinStrings (";") che è più idiomatico.
JacquesB

Sì, ci ho pensato dopo. A volte è bello poter specificare tutto in una volta sola, ma è decisamente più elegante dividere le operazioni :)
Jon Skeet

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

Dobbiamo convertire ciascuno degli elementi in a Stringprima di poterli unire, quindi ha senso usare Selecte un'espressione lambda. Questo è equivalente a mapin alcune altre lingue. Quindi dobbiamo riconvertire la raccolta di stringhe risultante in un array, perché String.Joinaccetta solo un array di stringhe.

Il ToArray()è un po 'brutto credo. String.Joindovrebbe davvero accettare IEnumerable<String>, non c'è motivo di restringerlo solo agli array. Questo probabilmente è solo perché Joinrisale a prima dei generici, quando gli array erano l'unico tipo di raccolta digitata disponibile.


5

Se il tuo array di numeri interi può essere grande, otterrai prestazioni migliori usando StringBuilder. Per esempio:

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

Modifica: quando ho pubblicato questo, avevo l'impressione errata che "StringBuilder.Append (int value)" fosse riuscito internamente ad aggiungere la rappresentazione di stringa del valore intero senza creare un oggetto stringa. Questo è sbagliato: l'ispezione del metodo con Reflector mostra che aggiunge semplicemente value.ToString ().

Pertanto l'unica potenziale differenza di prestazioni è che questa tecnica evita la creazione di un array e libera le stringhe per la garbage collection leggermente prima. In pratica questo non farà alcuna differenza misurabile, quindi ho votato positivamente questa soluzione migliore .


L'hai misurato per essere più veloce? String.Join utilizza anche uno StringBuilder.
JacquesB

Sì, ma prima devi convertire l'intera cosa in un array, il che è tutt'altro che ideale. In particolare, significa che devi avere tutte le stringhe convertite in memoria contemporaneamente, prima di iniziare a costruire la stringa risultante.
Jon Skeet,

OTOH String.Join calcola la dimensione del buffer di StringBuilder in modo da evitare il ridimensionamento. Quindi potrebbe essere più veloce anche se richiede più memoria.
JacquesB

5

La domanda è "il modo più semplice per convertirli in un'unica stringa in cui il numero è separato da un carattere".

Il modo più semplice è:

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: funziona solo in .NET 4.0+, ho perso il requisito .NET 3.5 la prima volta che ho letto la domanda.


Questo non è valido come metodo string.Join accetta solo un array di stringhe. Date un'occhiata qui msdn.microsoft.com/en-us/library/tk0xe5h0.aspx
ppolyzos

1
È un metodo sovraccarico: msdn.microsoft.com/en-us/library/dd988350 Ho appena copiato il codice che ho scritto in una nuova app console, aggiunto una Console.WriteLine e questo è l'output: 2,3,6,7
WebMasterP

1
Penso che questo sia disponibile solo in .net 4
Govind Malviya

Richiede un array di oggetti (o un array di stringhe), non un array int. Fornirà un errore "la chiamata è ambigua".
LarryBud

2

Sono d'accordo con l'espressione lambda per leggibilità e manutenibilità, ma non sarà sempre l'opzione migliore. Lo svantaggio dell'utilizzo di entrambi gli approcci IEnumerable / ToArray e StringBuilder è che devono far crescere dinamicamente un elenco, di elementi o caratteri, poiché non sanno quanto spazio sarà necessario per la stringa finale.

Se il raro caso in cui la velocità è più importante della concisione, quanto segue è più efficiente.

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

Ho anche pensato che ci fosse un modo più semplice. Non conosco la performance, qualcuno ha qualche idea (teorica)?


Questa soluzione ti darebbe ", 1,2,3,4,5".
Sarin

Grazie, ho aggiunto Substring(1)per risolverlo (era dalla memoria).
annullamento

2

In .NET 4.0, il join di stringa ha un overload per params object[], quindi è semplice come:

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

esempio

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

In .NET 2.0, è un po 'più difficile, poiché non c'è un tale sovraccarico. Quindi hai bisogno del tuo metodo generico:

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

In .NET 3.5 è possibile utilizzare metodi di estensione:

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

}

Quindi puoi usare il metodo di estensione JoinArray.

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

Puoi anche usare quel metodo di estensione in .NET 2.0, se aggiungi ExtensionAttribute al tuo codice:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.