TAK Skały! W niedzielę otrzymałem 3 doskonałe odpowiedzi w ciągu 10 minut!
Riri
4
Ponieważ .NET 4.0istnieją metody, które pobierają tablicę obiektów i IEnumerable, więc możesz to zrobić string.join(",", number). Wiem, że pytanie określa .NET 3.5, więc nie udzieliłem odpowiedzi, ale pojawia się w wyszukiwaniach, które nie określają wersji, a wiedza, że jest to możliwe w 4.0, może komuś pomóc.
Jason Goemaat
Odpowiedzi:
162
var ints =newint[]{1,2,3,4,5};var result =string.Join(",", ints.Select(x => x.ToString()).ToArray());Console.WriteLine(result);// prints "1,2,3,4,5"
EDYCJA : od (przynajmniej) .NET 4.5,
var result =string.Join(",", ints.Select(x => x.ToString()).ToArray());
jest równa:
var result =string.Join(",", ints);
EDYCJA :
Widzę, że kilka rozwiązań reklamuje użycie StringBuilder. Ktoś narzeka, że metoda Join powinna przyjmować argument IEnumerable.
Zawiodę Cię :) String.Join wymaga tablicy z jednego powodu - wydajności. Metoda Join musi znać rozmiar danych, aby skutecznie przydzielić niezbędną ilość pamięci.
Oto fragment wewnętrznej implementacji metody String.Join:
// length computed from length of items in input array and length of separatorstring str =FastAllocateString(length);fixed(char* chRef =&str.m_firstChar)// note than we use direct memory access here{UnSafeCharBuffer buffer =newUnSafeCharBuffer(chRef, length);
buffer.AppendString(value[startIndex]);for(int j = startIndex +1; j <= num2; j++){
buffer.AppendString(separator);
buffer.AppendString(value[j]);}}
Jestem zbyt leniwy, aby porównać wydajność sugerowanych metod. Ale coś mi mówi, że Join wygra :)
Jest to prawdopodobnie najlepszy zakład przy użyciu podstawowych metod rozszerzających .NET, ale naprawdę chciałem, aby string.Join () zaakceptował IEnumerable <string>, aby uniknąć konwersji ToArray ().
spoulson
Nic nie stoi na przeszkodzie, aby ktoś przeciążał string.Join, aby również wziąć IEnumerable. ;)
Robert P
1
Jest to prawdopodobnie również najłatwiejsze rozwiązanie, a nie tylko najszybsze.
Uważam, że istnieje wiele innych przypadków, w których użycie funkcji Convert.xxx jest lepszą alternatywą dla lambdy, chociaż w języku C # 3 lambda może pomóc w wnioskowaniu o typie.
Dość kompaktowa wersja C # 3, która współpracuje z .NET 2.0 to:
Jedną z mieszanin tych dwóch podejść byłoby napisanie metody rozszerzenia w IEnumerable <T>, która używała StringBuilder. Oto przykład z różnymi przeciążeniami w zależności od tego, czy chcesz określić transformację, czy po prostu polegać na zwykłym ToString. Nazwałem metodę „JoinStrings” zamiast „Join”, aby uniknąć pomyłki z innym typem Join. Może ktoś wymyśli lepszą nazwę :)
using System;
using System.Collections.Generic;
using System.Text;publicstaticclassExtensions{publicstaticstringJoinStrings<T>(thisIEnumerable<T> source,Func<T,string> projection,string separator){StringBuilder builder =newStringBuilder();bool first =true;foreach(T element in source){if(first){
first =false;}else{
builder.Append(separator);}
builder.Append(projection(element));}return builder.ToString();}publicstaticstringJoinStrings<T>(thisIEnumerable<T> source,string separator){returnJoinStrings(source, t => t.ToString(), separator);}}classTest{publicstaticvoidMain(){int[] x ={1,2,3,4,5,10,11};Console.WriteLine(x.JoinStrings(";"));Console.WriteLine(x.JoinStrings(i => i.ToString("X"),","));}}
Niezłe rozwiązanie! Nie potrzebujesz jednak parametru projekcji, możesz po prostu napisać x.Select (i => i.ToString ("X")). JoinStrings (";"), co jest bardziej idiomatyczne.
JacquesB
Tak, myślałem o tym później. Czasami miło jest móc określić to wszystko za jednym zamachem, ale zdecydowanie bardziej elegancko jest podzielić operacje :)
Musimy przekonwertować każdy z elementów na a, Stringzanim będziemy mogli je połączyć, więc sensowne jest użycie Selecti wyrażenie lambda. Jest to równoważne mapw niektórych innych językach. Następnie musimy przekonwertować wynikowy zbiór ciągów z powrotem na tablicę, ponieważString.Join akceptuje tylko tablicę ciągów.
ToArray()Jest nieco brzydki myślę. String.Joinpowinien naprawdę zaakceptować IEnumerable<String>, nie ma powodu, aby ograniczać go tylko do tablic. Dzieje się tak prawdopodobnie dlatego, że Joinpochodzi z czasów przed typami generycznymi, kiedy tablice były jedynym dostępnym rodzajem kolekcji.
Edycja: Kiedy to opublikowałem, miałem błędne wrażenie, że „StringBuilder.Append (int value)” wewnętrznie zdołał dołączyć ciąg znaków reprezentujący wartość całkowitą bez tworzenia obiektu ciągu. To jest złe: sprawdzanie metody za pomocą Reflectora pokazuje, że po prostu dołącza value.ToString ().
Dlatego jedyną potencjalną różnicą w wydajności jest to, że ta technika pozwala uniknąć tworzenia jednej tablicy i nieco wcześniej zwalnia ciągi do wyrzucania elementów bezużytecznych. W praktyce nie da to żadnej wymiernej różnicy, więc głosowałem za tym lepszym rozwiązaniem .
Czy zmierzyłeś, że jest szybszy? String.Join używa również StringBuilder.
JacquesB
Tak, ale najpierw musisz przekonwertować całość na tablicę, która jest daleka od ideału. W szczególności oznacza to, że musisz mieć wszystkie przekonwertowane ciągi w pamięci w tym samym czasie, zanim zaczniesz budować wynikowy ciąg.
Jon Skeet
OTOH String.Join wstępnie oblicza rozmiar buforu StringBuilder, aby uniknąć zmiany rozmiaru. Więc może być szybszy, nawet jeśli wymaga więcej pamięci.
JacquesB
5
Pytanie dotyczy „najłatwiejszego sposobu przekształcenia ich w pojedynczy ciąg, w którym liczby są oddzielone znakiem”.
Najłatwiej jest:
int[] numbers =newint[]{2,3,6,7};string number_string =string.Join(",", numbers);// do whatever you want with your exciting new number string
EDYCJA: To działa tylko w .NET 4.0+, brakowało mi wymagania .NET 3.5, gdy po raz pierwszy przeczytałem pytanie.
Jest to metoda przeciążona: msdn.microsoft.com/en-us/library/dd988350 Właśnie skopiowałem kod, który napisałem do nowej aplikacji konsolowej, dodałem Console.WriteLine i to jest wyjście: 2,3,6,7
WebMasterP,
1
Myślę, że jest to dostępne tylko w .net 4
Govind Malviya
Wymaga tablicy obiektów (lub tablicy ciągów), a nie tablicy int. Wystąpi błąd „połączenie jest niejednoznaczne”.
LarryBud
2
Zgadzam się z wyrażeniem lambda dotyczącym czytelności i łatwości konserwacji, ale nie zawsze będzie to najlepsza opcja. Wadą stosowania zarówno podejścia IEnumerable / ToArray, jak i StringBuilder jest to, że muszą one dynamicznie rozwijać listę elementów lub znaków, ponieważ nie wiedzą, ile miejsca będzie potrzebne na końcowy ciąg.
W rzadkich przypadkach, w których szybkość jest ważniejsza niż zwięzłość, bardziej efektywne są poniższe czynności.
int[] number =newint[]{1,2,3,4,5};string[] strings =newstring[number.Length];for(int i =0; i < number.Length; i++)
strings[i]= number[i].ToString();string result =string.Join(",", strings);
Dzięki, dodałem, Substring(1)żeby to naprawić (to było z pamięci).
nieważne
2
W .NET 4.0 łączenie ciągów ma przeciążenie dla params object[], więc jest tak proste, jak:
int[] ids =newint[]{1,2,3};string.Join(",", ids);
przykład
int[] ids =newint[]{1,2,3};System.Data.Common.DbCommand cmd =newSystem.Data.SqlClient.SqlCommand("SELECT * FROM some_table WHERE id_column IN (@bla)");
cmd.CommandText= cmd.CommandText.Replace("@bla",string.Join(",", ids));
W .NET 2.0 jest to trochę trudniejsze, ponieważ nie ma takiego przeciążenia. Potrzebujesz więc własnej ogólnej metody:
publicstaticstringJoinArray<T>(string separator, T[] inputTypeArray){string strRetValue =null;System.Collections.Generic.List<string> ls =newSystem.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;}
W .NET 3.5 można używać metod rozszerzających:
publicstaticclassArrayEx{publicstaticstringJoinArray<T>(this T[] inputTypeArray,string separator){string strRetValue =null;System.Collections.Generic.List<string> ls =newSystem.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;}}
Możesz również użyć tej metody rozszerzenia w .NET 2.0, jeśli dodasz ExtensionAttribute do swojego kodu:
// you need this once (only), and it must be in this namespace
namespace System.Runtime.CompilerServices{[AttributeUsage(AttributeTargets.Assembly|AttributeTargets.Class|AttributeTargets.Method)]publicsealedclassExtensionAttribute:Attribute{}}
.NET 4.0
istnieją metody, które pobierają tablicę obiektów i IEnumerable, więc możesz to zrobićstring.join(",", number)
. Wiem, że pytanie określa .NET 3.5, więc nie udzieliłem odpowiedzi, ale pojawia się w wyszukiwaniach, które nie określają wersji, a wiedza, że jest to możliwe w 4.0, może komuś pomóc.Odpowiedzi:
EDYCJA : od (przynajmniej) .NET 4.5,
jest równa:
EDYCJA :
Widzę, że kilka rozwiązań reklamuje użycie StringBuilder. Ktoś narzeka, że metoda Join powinna przyjmować argument IEnumerable.
Zawiodę Cię :) String.Join wymaga tablicy z jednego powodu - wydajności. Metoda Join musi znać rozmiar danych, aby skutecznie przydzielić niezbędną ilość pamięci.
Oto fragment wewnętrznej implementacji metody String.Join:
Jestem zbyt leniwy, aby porównać wydajność sugerowanych metod. Ale coś mi mówi, że Join wygra :)
źródło
using System.Linq;
jest wymagane.Chociaż w OP określono .NET 3.5, osoby, które chcą to zrobić w .NET 2.0 z C # 2, mogą to zrobić:
Uważam, że istnieje wiele innych przypadków, w których użycie funkcji Convert.xxx jest lepszą alternatywą dla lambdy, chociaż w języku C # 3 lambda może pomóc w wnioskowaniu o typie.
Dość kompaktowa wersja C # 3, która współpracuje z .NET 2.0 to:
źródło
Jedną z mieszanin tych dwóch podejść byłoby napisanie metody rozszerzenia w IEnumerable <T>, która używała StringBuilder. Oto przykład z różnymi przeciążeniami w zależności od tego, czy chcesz określić transformację, czy po prostu polegać na zwykłym ToString. Nazwałem metodę „JoinStrings” zamiast „Join”, aby uniknąć pomyłki z innym typem Join. Może ktoś wymyśli lepszą nazwę :)
źródło
Musimy przekonwertować każdy z elementów na a,
String
zanim będziemy mogli je połączyć, więc sensowne jest użycieSelect
i wyrażenie lambda. Jest to równoważnemap
w niektórych innych językach. Następnie musimy przekonwertować wynikowy zbiór ciągów z powrotem na tablicę, ponieważString.Join
akceptuje tylko tablicę ciągów.ToArray()
Jest nieco brzydki myślę.String.Join
powinien naprawdę zaakceptowaćIEnumerable<String>
, nie ma powodu, aby ograniczać go tylko do tablic. Dzieje się tak prawdopodobnie dlatego, żeJoin
pochodzi z czasów przed typami generycznymi, kiedy tablice były jedynym dostępnym rodzajem kolekcji.źródło
Jeśli twoja tablica liczb całkowitych może być duża, uzyskasz lepszą wydajność, używając StringBuilder. Na przykład:
Edycja: Kiedy to opublikowałem, miałem błędne wrażenie, że „StringBuilder.Append (int value)” wewnętrznie zdołał dołączyć ciąg znaków reprezentujący wartość całkowitą bez tworzenia obiektu ciągu. To jest złe: sprawdzanie metody za pomocą Reflectora pokazuje, że po prostu dołącza value.ToString ().
Dlatego jedyną potencjalną różnicą w wydajności jest to, że ta technika pozwala uniknąć tworzenia jednej tablicy i nieco wcześniej zwalnia ciągi do wyrzucania elementów bezużytecznych. W praktyce nie da to żadnej wymiernej różnicy, więc głosowałem za tym lepszym rozwiązaniem .
źródło
Pytanie dotyczy „najłatwiejszego sposobu przekształcenia ich w pojedynczy ciąg, w którym liczby są oddzielone znakiem”.
Najłatwiej jest:
EDYCJA: To działa tylko w .NET 4.0+, brakowało mi wymagania .NET 3.5, gdy po raz pierwszy przeczytałem pytanie.
źródło
Zgadzam się z wyrażeniem lambda dotyczącym czytelności i łatwości konserwacji, ale nie zawsze będzie to najlepsza opcja. Wadą stosowania zarówno podejścia IEnumerable / ToArray, jak i StringBuilder jest to, że muszą one dynamicznie rozwijać listę elementów lub znaków, ponieważ nie wiedzą, ile miejsca będzie potrzebne na końcowy ciąg.
W rzadkich przypadkach, w których szybkość jest ważniejsza niż zwięzłość, bardziej efektywne są poniższe czynności.
źródło
Pomyślałem też, że istnieje prostszy sposób. Nie wiesz o wydajności, ktoś ma jakiś (teoretyczny) pomysł?
źródło
Substring(1)
żeby to naprawić (to było z pamięci).W .NET 4.0 łączenie ciągów ma przeciążenie dla
params object[]
, więc jest tak proste, jak:przykład
W .NET 2.0 jest to trochę trudniejsze, ponieważ nie ma takiego przeciążenia. Potrzebujesz więc własnej ogólnej metody:
W .NET 3.5 można używać metod rozszerzających:
Możesz więc użyć metody rozszerzenia JoinArray.
Możesz również użyć tej metody rozszerzenia w .NET 2.0, jeśli dodasz ExtensionAttribute do swojego kodu:
źródło
Możesz to zrobić
Sprawdzić
Separator Delimited ToString dla Array, List, Dictionary, Generic IEnumerable
źródło
zapomnij o .net 3.5 i użyj następnego kodu w .net core
źródło