LINQ का उपयोग स्ट्रिंग्स को समतल करने के लिए


346

पुराने स्कूल को लिखने का सबसे कुशल तरीका क्या है:

StringBuilder sb = new StringBuilder();
if (strings.Count > 0)
{
    foreach (string s in strings)
    {
        sb.Append(s + ", ");
    }
    sb.Remove(sb.Length - 2, 2);
}
return sb.ToString();

... LINQ में?


1
क्या आपने चीजों को करने के किसी अन्य सुपर कूल LINQ तरीके की खोज की?
रॉबर्ट एस।

3
अच्छी तरह से चयनित उत्तर और अन्य सभी विकल्प Linq में Entities के लिए काम नहीं करते हैं।
बिनोज एंटनी जूल

3
@ बिनोज एंटनी, अपने डेटाबेस को स्ट्रिंग कॉन्सेप्टन न करें।
एमी बी

6
@ Pr0fess0rX: क्योंकि यह नहीं हो सकता है और यह नहीं होना चाहिए। मैं अन्य डेटाबेस के बारे में नहीं जानता, लेकिन SQL सर्वर में आप केवल (n) varcahr को समाप्‍त कर सकते हैं, जो आपको (n) varchar (अधिकतम) तक सीमित करता है। ऐसा नहीं होना चाहिए क्योंकि व्यावसायिक तर्क को डेटा लेयर में लागू नहीं किया जाना चाहिए।
the_drow

पूर्ण स्रोत कोड और उच्च प्रदर्शन के साथ कोई अंतिम समाधान?
किकेनेट

जवाबों:


529

यह उत्तर Aggregateप्रश्न में अनुरोध के अनुसार LINQ ( ) का उपयोग दिखाता है और रोजमर्रा के उपयोग के लिए अभिप्रेत नहीं है। क्योंकि यह उपयोग नहीं करता है StringBuilderयह बहुत लंबे दृश्यों के लिए भयानक प्रदर्शन होगा। String.Joinअन्य उत्तर में दिखाए गए अनुसार नियमित कोड उपयोग के लिए

इस तरह कुल प्रश्नों का उपयोग करें:

string[] words = { "one", "two", "three" };
var res = words.Aggregate(
   "", // start with empty string to handle empty list case.
   (current, next) => current + ", " + next);
Console.WriteLine(res);

यह आउटपुट:

, एक दो तीन

एक समुच्चय एक फ़ंक्शन है जो मानों का संग्रह लेता है और एक स्केलर मान लौटाता है। टी-एसक्यूएल के उदाहरणों में न्यूनतम, अधिकतम और योग शामिल हैं। VB और C # दोनों को समुच्चय का समर्थन है। VB और C # दोनों एक्‍सटेंशन विधियों के रूप में एकत्रित होते हैं। डॉट-नोटेशन का उपयोग करते हुए, कोई बस एक IEnumerable ऑब्जेक्ट पर एक विधि कहता है ।

याद रखें कि समग्र प्रश्नों को तुरंत निष्पादित किया जाता है।

अधिक जानकारी - MSDN: क्वेरीज़ अलग करें


यदि आप वास्तव में CodeMonkeyKing द्वारा प्रस्तावित टिप्पणी Aggregateका उपयोग करके वेरिएंट का उपयोग करना चाहते हैं, जो समान कोड के बारे में होगा, जिसमें बड़ी संख्या में वस्तुओं के लिए अच्छा प्रदर्शन शामिल है:StringBuilderString.Join

 var res = words.Aggregate(
     new StringBuilder(), 
     (current, next) => current.Append(current.Length == 0? "" : ", ").Append(next))
     .ToString();

4
पहला उदाहरण "एक, दो, तीन" का आउटपुट नहीं देता है, यह "आउटपुट,", एक, दो, तीन "(प्रमुख कॉमा को नोटिस करें)।
मृत्यु

आपके पहले उदाहरण में, जब से आप बीज लेते हैं "", पहले मूल्य का उपयोग currentएक खाली स्ट्रिंग में होता है। तो, 1 या अधिक तत्व के लिए, आपको हमेशा , स्ट्रिंग की शुरुआत में मिलेगा ।
माइकल यन्नी

@ मुझे यह तय हो गया है
सर्गट

358
return string.Join(", ", strings.ToArray());

.Net 4 में, उस स्वीकार के लिए एक नया अधिभार है । फिर कोड इस तरह दिखेगा:string.JoinIEnumerable<string>

return string.Join(", ", strings);

2
ठीक है, इसलिए समाधान Linq का उपयोग नहीं करता है, लेकिन यह मुझे बहुत अच्छी तरह से काम करने लगता है
Mat Roberts

33
ToArray is linq :)
एमी बी

18
यह सबसे सही उत्तर है। यह प्रश्न और स्वीकृत उत्तर दोनों की तुलना में तेज़ है और यह एग्रीगेट की तुलना में बहुत अधिक स्पष्ट है, जिसका उपयोग करने पर हर बार पैराग्राफ-लंबी व्याख्या की आवश्यकता होती है।
PRMan

@realPro पूरी तरह से गलत है। github.com/microsoft/referencesource/blob/master/mscorlib/… रेखा 161
एमी बी

125

Linq का उपयोग क्यों करें?

string[] s = {"foo", "bar", "baz"};
Console.WriteLine(String.Join(", ", s));

यह पूरी तरह से काम करता है और IEnumerable<string>जहां तक ​​मुझे याद है किसी भी स्वीकार करता है। Aggregateयहाँ कुछ भी नहीं चाहिए जो बहुत धीमा हो।


19
सीखना LINQ शांत हो सकता है, और LINQ अंत को पूरा करने के लिए एक प्यारा साधन हो सकता है, लेकिन वास्तव में अंतिम परिणाम प्राप्त करने के लिए LINQ का उपयोग करना बुरा होगा, अगर कम से कम मूर्खतापूर्ण नहीं कहा जाए
जेसन बंटिंग

9
.NET 4.0 में IEnumerable <string> और IEnumrable <T> अधिभार है, जो इसे उपयोग करने के लिए बहुत आसान बना देगा
Cine

3
जैसा कि सिने बताते हैं, .NET 4.0 में अधिभार है। पिछले संस्करण नहीं। आप अभी भी String.Join(",", s.ToArray())पुराने संस्करणों में रह सकते हैं ।
मार्टिज़न


@ शोग 9 मर्जिंग यहाँ जवाबों को दोहराए गए प्रयासों की तरह बनाता है, और टाइमस्टैम्प बिल्कुल भी मदद नहीं करते हैं .. फिर भी जाने का रास्ता।
नवाफाल

77

क्या आपने एग्रीगेट एक्सटेंशन पद्धति को देखा है?

var sa = (new[] { "yabba", "dabba", "doo" }).Aggregate((a,b) => a + "," + b);

23
यह शायद String.Join () की तुलना में धीमा है, और कोड में पढ़ने के लिए कठिन है। प्रश्न का उत्तर "LINQ तरीका" के लिए दिया गया है, हालांकि :-)
क्रिस वेन्हम

5
हाँ, मैं अपनी राय के साथ जवाब नहीं देना चाहता था। : पी
रॉबर्ट एस।

2
यह वास्तव में काफी थोड़ा धीमा है, वास्तव में। यहां तक ​​कि सहमति के बजाय स्ट्रिंगबर्ल के साथ एग्रीगेट का उपयोग करना स्ट्रिंग की तुलना में धीमा है।
जोएल मुलर

4
10.000.000 पुनरावृत्तियों के साथ एक परीक्षण किया गया, कुल 4.3 सेकंड और string.join 2.3 सेकंड लिया गया। इसलिए मैं कहूंगा कि 99% आम उपयोग के मामलों में पूर्ण भिन्नता महत्वहीन है। इसलिए यदि आप पहले से ही अपने डेटा को संसाधित करने के लिए बहुत सारे लाइनक कर रहे हैं, तो आमतौर पर उस अच्छे वाक्यविन्यास को तोड़ने और string.jpg imo का उपयोग करने की कोई आवश्यकता नहीं है। gist.github.com/joeriks/5791981
joeriks


56

मेरे कोड से वास्तविक उदाहरण:

return selected.Select(query => query.Name).Aggregate((a, b) => a + ", " + b);

क्वेरी एक ऐसी वस्तु है जिसमें एक नाम गुण होता है जो एक स्ट्रिंग है, और मैं चयनित सूची पर सभी प्रश्नों के नाम चाहता हूं, जिन्हें अल्पविराम से अलग किया गया है।


2
प्रदर्शन के बारे में टिप्पणियों को देखते हुए, मुझे यह जोड़ना चाहिए कि उदाहरण उस कोड से है जो एक बार डायलॉग बंद होने पर चलता है, और सूची के उस पर लगभग दस से अधिक तार होने की संभावना नहीं है!
डैनियल ईयरविकर

किसी भी सुराग कैसे Linq Entities में यह एक ही कार्य करने के लिए?
बिनोज एंटनी जूल

1
बहुत बढ़िया उदाहरण है। इसे वास्तविक विश्व परिदृश्य में डालने के लिए धन्यवाद। मेरे पास एक ही सटीक स्थिति थी, एक वस्तु की संपत्ति के साथ जिसे संक्षिप्त करने की आवश्यकता थी।
जेसी होउले

1
मेरी सूची <T>
निक्की 9696

1
कृपया बड़े सरणी के साथ इस दृष्टिकोण के प्रदर्शन के बारे में लिखें।
Giulio Caccin

31

यहाँ संयुक्त जॉइन / लाइनक दृष्टिकोण है जो मैं अन्य उत्तरों और एक समान प्रश्न में संबोधित मुद्दों (जैसे कि एग्रीगेट और कॉन्टेनेटेट 0 तत्वों के साथ विफल रहता है) को देखने के बाद मैं पर बस गया ।

string Result = String.Join(",", split.Select(s => s.Name));

या (यदि sएक स्ट्रिंग नहीं है)

string Result = String.Join(",", split.Select(s => s.ToString()));

  • सरल
  • पढ़ने और समझने में आसान
  • सामान्य तत्वों के लिए काम करता है
  • ऑब्जेक्ट या ऑब्जेक्ट प्रॉपर्टी का उपयोग करने की अनुमति देता है
  • 0-लंबाई वाले तत्वों के मामले को संभालता है
  • अतिरिक्त Linq फ़िल्टरिंग के साथ इस्तेमाल किया जा सकता है
  • अच्छा प्रदर्शन करता है (कम से कम मेरे अनुभव में)
  • StringBuilderलागू करने के लिए एक अतिरिक्त वस्तु (जैसे ) के निर्माण (मैनुअल) की आवश्यकता नहीं है

और निश्चित रूप से जॉइन pesky अंतिम अल्पविराम का ख्याल रखता है जो कभी-कभी अन्य दृष्टिकोणों ( for, foreach) में बोलता है , यही वजह है कि मैं पहले स्थान पर एक Linq समाधान की तलाश कर रहा था।


1
मिस-मैचेड कोष्ठक।
ctrl-alt-delor


3
मुझे यह उत्तर पसंद है क्योंकि .Select()इस तरह का उपयोग करना इस ऑपरेशन के दौरान प्रत्येक तत्व को संशोधित करने के लिए एक आसान स्थान प्रदान करता है। उदाहरण के लिए, प्रत्येक वस्तु को किसी पात्र में लपेटना जैसे किstring Result = String.Join(",", split.Select(s => "'" + s + "'"));
सैम स्टैररी

29

आप उपयोग कर सकते हैं StringBuilderमें Aggregate:

  List<string> strings = new List<string>() { "one", "two", "three" };

  StringBuilder sb = strings
    .Select(s => s)
    .Aggregate(new StringBuilder(), (ag, n) => ag.Append(n).Append(", "));

  if (sb.Length > 0) { sb.Remove(sb.Length - 2, 2); }

  Console.WriteLine(sb.ToString());

( Selectवहाँ है सिर्फ दिखाने के लिए आप और अधिक LINQ सामान कर सकते हैं।)


2
+1 अच्छा। हालांकि, IMO अतिरिक्त जोड़ने से बचने के लिए बेहतर है "," बाद में इसे मिटाने के लिए। कुछ इस तरहnew[] {"one", "two", "three"}.Aggregate(new StringBuilder(), (sb, s) =>{if (sb.Length > 0) sb.Append(", ");sb.Append(s);return sb;}).ToString();
dss539

5
आप if (length > 0)linq में जाँच नहीं करके और इसे बाहर निकालकर कीमती घड़ी चक्रों को बचाएंगे ।
बीनोज एंटनी

1
मैं dss539 से सहमत हूं। मेरा संस्करणnew[] {"", "one", "two", "three"}.Aggregate(new StringBuilder(), (sb, s) => (String.IsNullOrEmpty(sb.ToString())) ? sb.Append(s) : sb.Append(", ").Append(s)).ToString();
22

22

3000 से अधिक तत्वों के लिए StringBuilder बनाम चुनें और सकल मामले के लिए त्वरित प्रदर्शन डेटा:

इकाई परीक्षण - अवधि (सेकंड)
LINQ_StringBuilder - 0.0036644
LINQ_Select.Aggregate - 1.8012535

    [TestMethod()]
    public void LINQ_StringBuilder()
    {
        IList<int> ints = new List<int>();
        for (int i = 0; i < 3000;i++ )
        {
            ints.Add(i);
        }
        StringBuilder idString = new StringBuilder();
        foreach (int id in ints)
        {
            idString.Append(id + ", ");
        }
    }
    [TestMethod()]
    public void LINQ_SELECT()
    {
        IList<int> ints = new List<int>();
        for (int i = 0; i < 3000; i++)
        {
            ints.Add(i);
        }
        string ids = ints.Select(query => query.ToString())
                         .Aggregate((a, b) => a + ", " + b);
    }

इसके लिए गैर LINQ मार्ग पर जाने का निर्णय लेने में मददगार
crabCRUSHERclamCOLLECTOR

4
समय का अंतर शायद StringBuilder बनाम स्ट्रिंग संबंध का उपयोग कर + है। LINQ या Aggregate का कोई लेना देना नहीं है। LINQ एग्रीगेट (SO पर बहुत सारे उदाहरण) में StringBuilder रखो, और यह बस के रूप में तेजी से होना चाहिए।
कंट्रोलबॉक्स

16

मैं हमेशा एक्सटेंशन विधि का उपयोग करता हूं:

public static string JoinAsString<T>(this IEnumerable<T> input, string seperator)
{
    var ar = input.Select(i => i.ToString()).ToArray();
    return string.Join(seperator, ar);
}

5
string.Joinमें .net 4 पहले से ही IEnumerable<T>किसी भी मनमानी के लिए ले जा सकता है T
पुनरावर्ती


12

' सुपर-कूल LINQ तरीका ' द्वारा आप उस तरीके के बारे में बात कर रहे होंगे जिस तरह से LINQ एक्सटेंशन प्रोग्रामिंग के उपयोग के साथ कार्यात्मक प्रोग्रामिंग को बहुत अधिक प्रभावशाली बनाता है। मेरा मतलब है, वाक्यगत शर्करा जो कार्यों को नेत्रहीन रैखिक तरीके से (एक के बाद एक) घोंसले के शिकार के बजाय (दूसरे के अंदर एक) में जंजीर की अनुमति देता है। उदाहरण के लिए:

int totalEven = Enumerable.Sum(Enumerable.Where(myInts, i => i % 2 == 0));

इस तरह लिखा जा सकता है:

int totalEven = myInts.Where(i => i % 2 == 0).Sum();

आप देख सकते हैं कि दूसरा उदाहरण पढ़ना कितना आसान है। आप यह भी देख सकते हैं कि इंडेंटेशन समस्याओं के कम या अभिव्यक्ति के अंत में दिखने वाले लिस्फी क्लोजिंग परेंस के साथ और अधिक फ़ंक्शन कैसे जोड़े जा सकते हैं ।

बहुत सारे अन्य उत्तर बताते हैं कि जाने String.Joinका तरीका है क्योंकि यह पढ़ने में सबसे तेज या सरल है। लेकिन अगर आप ' सुपर-कूल LINQ तरीके ' की मेरी व्याख्या लेते हैं, तो इसका उत्तर उपयोग करना है, String.Joinलेकिन क्या यह एक LINQ शैली विस्तार पद्धति में लिपटा है, जो आपको नेत्रहीन रूप से अपने कार्यों की श्रृंखला बनाने की अनुमति देगा। इसलिए अगर आप लिखना चाहते हैं तो आपको sa.Concatenate(", ")कुछ इस तरह से बनाने की जरूरत है:

public static class EnumerableStringExtensions
{
   public static string Concatenate(this IEnumerable<string> strings, string separator)
   {
      return String.Join(separator, strings);
   }
}

यह कोड प्रदान करेगा जो प्रत्यक्ष कॉल के रूप में (कम से कम एल्गोरिथम जटिलता के संदर्भ में) और कुछ मामलों में कोड को अधिक पठनीय बना सकता है (संदर्भ के आधार पर) विशेष रूप से यदि ब्लॉक में अन्य कोड जंजीर फ़ंक्शन शैली का उपयोग कर रहा है ।


1
इस थ्रेड में टाइपो की संख्या पागल है: सेपरेटर => सेपरेटर, कॉनसेटिनेट =>
कॉनसेटनेट


5

इस पिछले प्रश्न पर विभिन्न वैकल्पिक उत्तर हैं - जो स्रोत के रूप में एक पूर्णांक सरणी को लक्षित कर रहे थे, लेकिन सामान्यीकृत उत्तर प्राप्त हुए।


5

यहाँ यह शुद्ध LINQ को एकल अभिव्यक्ति के रूप में उपयोग कर रहा है:

static string StringJoin(string sep, IEnumerable<string> strings) {
  return strings
    .Skip(1)
    .Aggregate(
       new StringBuilder().Append(strings.FirstOrDefault() ?? ""), 
       (sb, x) => sb.Append(sep).Append(x));
}

और इसकी बहुत तेजी से लानत है!


3

मैं थोड़ा धोखा देने जा रहा हूं और इस बारे में एक नया जवाब निकालता हूं जो एक टिप्पणी के अंदर चिपकाने के बजाय यहां पर सब कुछ का सबसे अच्छा योग करने के लिए लगता है।

तो आप इसे एक लाइन कर सकते हैं:

List<string> strings = new List<string>() { "one", "two", "three" };

string concat = strings        
    .Aggregate(new StringBuilder("\a"), 
                    (current, next) => current.Append(", ").Append(next))
    .ToString()
    .Replace("\a, ",string.Empty); 

संपादित करें: आप या तो पहले एक खाली गणना के लिए जाँच करना चाहते हैं या .Replace("\a",string.Empty);अभिव्यक्ति के अंत में जोड़ देंगे । लगता है कि मैं थोड़ा बहुत स्मार्ट होने की कोशिश कर रहा था।

@ A.friend से उत्तर थोड़ा अधिक प्रदर्शनकारी हो सकता है, मुझे यकीन नहीं है कि निकालें की तुलना में हुड के नीचे रिप्लेसमेंट क्या करता है। केवल अन्य कैवेट यदि किसी कारण से आप स्ट्रिंग्स को समाप्‍त करना चाहते थे जो कि आप में समाप्त हो गया है तो आप अपने विभाजकों को खो देंगे ... मुझे लगता है कि संभावना नहीं है। यदि ऐसा है तो आपके पास चुनने के लिए अन्य फैंसी चरित्र हैं।


2

आप LINQ और string.join()काफी प्रभावी ढंग से जोड़ सकते हैं । यहां मैं एक स्ट्रिंग से एक आइटम निकाल रहा हूं। ऐसा करने के बेहतर तरीके भी हैं लेकिन यहाँ यह है:

filterset = String.Join(",",
                        filterset.Split(',')
                                 .Where(f => mycomplicatedMatch(f,paramToMatch))
                       );


1

पसंद के बहुत सारे यहाँ। आप LINQ और StringBuilder का उपयोग कर सकते हैं ताकि आपको प्रदर्शन भी पसंद आए:

StringBuilder builder = new StringBuilder();
List<string> MyList = new List<string>() {"one","two","three"};

MyList.ForEach(w => builder.Append(builder.Length > 0 ? ", " + w : w));
return builder.ToString();

builder.Length > 0फॉरएच में जाँच न करना और फ़ोरइच के बाद पहला कॉमा हटाकर तेज़ करना आसान होगा
बिनोज एंटनी

1

जब आईआईएस लॉग फाइल को लाइनक का उपयोग करते हुए मैंने निम्नलिखित त्वरित और गंदा किया, तो इसने @ 1 मिलियन लाइनों को बहुत अच्छी तरह से (15 सेकंड) काम किया, हालाँकि 2 लाख लाइनों की कोशिश करने पर मेमोरी त्रुटि से बाहर निकला।

    static void Main(string[] args)
    {

        Debug.WriteLine(DateTime.Now.ToString() + " entering main");

        // USED THIS DOS COMMAND TO GET ALL THE DAILY FILES INTO A SINGLE FILE: copy *.log target.log 
        string[] lines = File.ReadAllLines(@"C:\Log File Analysis\12-8 E5.log");

        Debug.WriteLine(lines.Count().ToString());

        string[] a = lines.Where(x => !x.StartsWith("#Software:") &&
                                      !x.StartsWith("#Version:") &&
                                      !x.StartsWith("#Date:") &&
                                      !x.StartsWith("#Fields:") &&
                                      !x.Contains("_vti_") &&
                                      !x.Contains("/c$") &&
                                      !x.Contains("/favicon.ico") &&
                                      !x.Contains("/ - 80")
                                 ).ToArray();

        Debug.WriteLine(a.Count().ToString());

        string[] b = a
                    .Select(l => l.Split(' '))
                    .Select(words => string.Join(",", words))
                    .ToArray()
                    ;

        System.IO.File.WriteAllLines(@"C:\Log File Analysis\12-8 E5.csv", b);

        Debug.WriteLine(DateTime.Now.ToString() + " leaving main");

    }

वास्तविक रूप से मैंने लिन्क का उपयोग एक डिस्टिंक्ट के लिए किया था () मुझे पहले से ज़रूरत थी:

string[] b = a
    .Select(l => l.Split(' '))
    .Where(l => l.Length > 11)
    .Select(words => string.Format("{0},{1}",
        words[6].ToUpper(), // virtual dir / service
        words[10]) // client ip
    ).Distinct().ToArray()
    ;


0

मैंने कुछ समय पहले इसके बारे में ब्लॉग किया था, मैंने जो कुछ देखा उसके लिए आप क्या करते हैं:

http://ondevelopment.blogspot.com/2009/02/string-concatenation-made-easy.html

ब्लॉग पोस्ट में यह वर्णन किया गया है कि विस्तार के तरीकों को कैसे लागू किया जाए जो IEnumerable पर काम करते हैं और जिन्हें Concatenate नाम दिया गया है, इससे आपको कुछ चीजें बताएंगे:

var sequence = new string[] { "foo", "bar" };
string result = sequence.Concatenate();

या अधिक विस्तृत बातें जैसे:

var methodNames = typeof(IFoo).GetMethods().Select(x => x.Name);
string result = methodNames.Concatenate(", ");


क्या आप यहां कोड को संकलित कर सकते हैं ताकि उत्तर समझने में आसान हो?
Giulio Caccin
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.