मैं IEnumerable <T> संग्रह में एक आइटम कैसे जोड़ सकता हूं?


405

शीर्षक के रूप में मेरा प्रश्न। उदाहरण के लिए,

IEnumerable<T> items = new T[]{new T("msg")};
items.ToList().Add(new T("msg2"));

लेकिन आखिरकार इसमें केवल 1 आइटम है।

क्या हमारे पास एक तरीका हो सकता है items.Add(item)?

की तरह List<T>


4
IEnumerable<T>केवल संग्रह संग्रहण के लिए है। यह LINQ फ्रेमवर्क के लिए बैकबोन है। यह हमेशा इस तरह के रूप में कुछ अन्य संग्रह का एक अमूर्त है Collection<T>, List<T>या Array। इंटरफ़ेस केवल एक ऐसी GetEnumeratorविधि प्रदान करता है जो इसका एक उदाहरण देता है जो IEnumerator<T>एक समय में एक संग्रह में एक आइटम को चलाने में सक्षम बनाता है। LINQ एक्सटेंशन विधियाँ इस इंटरफ़ेस द्वारा सीमित हैं। IEnumerable<T>केवल इसलिए पढ़ा जा सकता है क्योंकि यह कई संग्रह के कुछ हिस्सों का प्रतिनिधित्व करता है।
जॉर्डन

3
इस उदाहरण के लिए, बस IList<T>इसके बजाय घोषित करें IEnumerable<T>:IList<T> items = new T[]{new T("msg")}; items.Add(new T("msg2"));
NightOwl888

जवाबों:


480

आप नहीं कर सकते, क्योंकि IEnumerable<T>आवश्यक रूप से एक संग्रह का प्रतिनिधित्व नहीं करता है जिसमें आइटम जोड़े जा सकते हैं। वास्तव में, यह बिल्कुल एक संग्रह का प्रतिनिधित्व नहीं करता है! उदाहरण के लिए:

IEnumerable<string> ReadLines()
{
     string s;
     do
     {
          s = Console.ReadLine();
          yield return s;
     } while (!string.IsNullOrEmpty(s));
}

IEnumerable<string> lines = ReadLines();
lines.Add("foo") // so what is this supposed to do??

हालांकि, आप क्या कर सकते हैं, एक नई IEnumerable वस्तु (अनिर्दिष्ट प्रकार की) बना रहा है, जो कि जब एनुमरेट किया जाता है, तो पुराने सभी आइटमों को प्रदान करेगा, साथ ही साथ कुछ अपने स्वयं के। आप इसके लिए उपयोग Enumerable.Concatकरते हैं:

 items = items.Concat(new[] { "foo" });

यह ऐरे ऑब्जेक्ट को नहीं बदलेगा (आप एरेज़ में आइटम नहीं डाल सकते हैं, वैसे भी)। लेकिन यह एक नया ऑब्जेक्ट बनाएगा जो सभी आइटम को सरणी में सूचीबद्ध करेगा, और फिर "फू"। इसके अलावा, वह नई वस्तु होगी सरणी में परिवर्तनों का ट्रैक रखेगा (यानी जब भी आप इसे एन्यूमरेट करेंगे, आपको आइटमों के वर्तमान मूल्य दिखाई देंगे)।


3
ओवरहेड पर एकल मान जोड़ने के लिए एक सरणी बनाना थोड़ा अधिक है। एक एकल मान कॉनसैट के लिए एक विस्तार विधि को परिभाषित करने के लिए यह थोड़ा अधिक पुन: प्रयोज्य है।
जेयरपावर

4
यह निर्भर करता है - यह इसके लायक हो सकता है, लेकिन मैं इसे समय से पहले अनुकूलन कहकर लुभाता हूं जब तक Concatकि इसे बार-बार लूप में नहीं बुलाया जाता है; और अगर यह है, तो आप वैसे भी बड़ी समस्याएँ हैं, क्योंकि हर बार जब आप Concat, आपको एन्यूमरेटर की एक और परत मिलती है - तो इसके अंत तक एकल कॉल के MoveNextपरिणामस्वरूप पुनरावृत्तियों की संख्या के बराबर कॉल की एक श्रृंखला हो जाएगी।
पावेल मिनाएव

2
@ पावेल, हेह। आमतौर पर यह उस सरणी को बनाने की स्मृति नहीं है जो मुझे परेशान करती है। यह अतिरिक्त टाइपिंग है जो मुझे कष्टप्रद लगता है :)।
जारेपियर जूल

2
इसलिए मैं थोड़ा और समझता हूं कि IEnumerable क्या करता है। यह केवल देखने का इरादा नहीं होना चाहिए। धन्यवाद दोस्तों
ldsenow

7
मैं के लिए वाक्यात्मक चीनी के लिए एक कनेक्ट सुविधा का अनुरोध किया था IEnumerable<T>अधिक भार सहित सी # में, operator+के रूप में Concat(वैसे, आप जानते हैं कि VB में, आप सूचकांक कर सकते हैं IEnumerableजैसे कि वह एक सरणी था - इसे इस्तेमाल करता है ElementAtहुड के नीचे): connect.microsoft.com / VisualStudio / प्रतिक्रिया /… । हम भी की दो और भार के मिलता है Concatदोनों को छोड़ दिया पर और सही पर एक आइटम लेने के लिए, यह करने के लिए टाइपिंग नीचे में कटौती करेगा xs +=x - तो जाना प्रहार मैड्स (Torgersen) सी # 5.0 में :) इस प्राथमिकता देने के लिए
पावेल Minaev

98

प्रकार IEnumerable<T>इस तरह के संचालन का समर्थन नहीं करता है। IEnumerable<T>इंटरफ़ेस का उद्देश्य एक उपभोक्ता को एक संग्रह की सामग्री को देखने की अनुमति देना है। मूल्यों को संशोधित करने के लिए नहीं।

जब आप जैसे संचालन करते हैं .ToList () जोड़ें। () आप एक नया बना रहे हैं List<T>और उस सूची में एक मान जोड़ रहे हैं । इसका मूल सूची से कोई संबंध नहीं है।

आप जो भी कर सकते हैं, IEnumerable<T>वह जोड़ा गया मूल्य के साथ एक नया बनाने के लिए जोड़ें विस्तार विधि का उपयोग करें ।

items = items.Add("msg2");

इस मामले में भी यह मूल IEnumerable<T>वस्तु को संशोधित नहीं करेगा । यह एक संदर्भ धारण करके सत्यापित किया जा सकता है। उदाहरण के लिए

var items = new string[]{"foo"};
var temp = items;
items = items.Add("bar");

परिचालनों के इस सेट के बाद परिवर्तनीय अस्थायी अभी भी मूल्यों के सेट में एक एकल तत्व "फू" के साथ एक enumerable को संदर्भित करेगा, जबकि आइटम "foo" और "बार" के साथ एक अलग गणना योग्य का संदर्भ देंगे।

संपादित करें

मैं लगातार यह भूल जाता हूं कि Add एक विशिष्ट विस्तार विधि नहीं है IEnumerable<T>क्योंकि यह उन पहले में से एक है जिसे मैं परिभाषित करता हूं। यह रहा

public static IEnumerable<T> Add<T>(this IEnumerable<T> e, T value) {
  foreach ( var cur in e) {
    yield return cur;
  }
  yield return value;
}

12
इसे कहा जाता है Concat:)
पावेल मिनावे

3
@ पावेल, इस ओर इशारा करने के लिए धन्यवाद। हालांकि कॉनकैट भी काम नहीं करेगा, क्योंकि यह एक और IEnumerable <T> लेता है। मैंने अपनी परियोजनाओं में परिभाषित विशिष्ट विस्तार पद्धति को चिपकाया।
जारेदपार

10
मैं Addहालांकि यह नहीं कहूंगा , क्योंकि Addवस्तुतः किसी भी अन्य .NET प्रकार (न केवल संग्रह) संग्रह में जगह को बदल देता है। हो सकता है With? या यह भी एक और अधिभार हो सकता है Concat
पावेल मिनाव

4
मैं मानता हूं कि Concatअधिभार शायद एक बेहतर विकल्प होगा क्योंकि Addआमतौर पर उत्परिवर्तन का मतलब होता है।
दान अब्रामोव

15
शरीर को संशोधित करने के बारे में क्या return e.Concat(Enumerable.Repeat(value,1));?
रॉय टिंकर

58

क्या आपने उपयोग करने पर विचार किया है ICollection<T>IList<T> इसके बजाय या इंटरफेस किया है, वे बहुत ही इस कारण से मौजूद हैं कि आप एक Addविधि चाहते हैं IEnumerable<T>

IEnumerable<T>एक प्रकार के रूप में 'मार्क' करने के लिए उपयोग किया जाता है ... अच्छी तरह से, पर्याप्त या आवश्यक वस्तुओं के एक अनुक्रम के बिना आवश्यक है कि क्या वास्तविक अंतर्निहित वस्तु वस्तुओं को जोड़ने / हटाने का समर्थन करती है। यह भी याद रखें कि ये इंटरफेस लागू होते हैं IEnumerable<T>इसलिए आपको उन सभी एक्सटेंशन विधियों को प्राप्त होता है जो आपको मिलती हैंIEnumerable<T>


31

एक छोटे से, मीठे विस्तार के तरीकों पर IEnumerableऔर IEnumerable<T>मेरे लिए करो:

public static IEnumerable Append(this IEnumerable first, params object[] second)
{
    return first.OfType<object>().Concat(second);
}
public static IEnumerable<T> Append<T>(this IEnumerable<T> first, params T[] second)
{
    return first.Concat(second);
}   
public static IEnumerable Prepend(this IEnumerable first, params object[] second)
{
    return second.Concat(first.OfType<object>());
}
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first, params T[] second)
{
    return second.Concat(first);
}

सुरुचिपूर्ण (अच्छी तरह से, गैर-सामान्य संस्करणों को छोड़कर)। बहुत बुरा ये तरीके बीसीएल में नहीं हैं।


पहला Prepend तरीका मुझे एक त्रुटि दे रहा है। "ऑब्जेक्ट [] 'में' कॉनसैट 'के लिए परिभाषा नहीं है और सबसे अच्छा विस्तार विधि' अधिभार 'System.Linq.Enumerable.Concat <TSource> (System.Collections.Generic.IEVumerable <TSource>, System.Collections.Generic) है। IEnumerable <TSource>) 'के कुछ अमान्य तर्क हैं "
टिम न्यूटन

@TimNewton आप इसे गलत कर रहे हैं। कौन जानता है कि क्यों, कोई भी त्रुटि कोड के उस स्निपेट से नहीं बता सकता है। Protip: हमेशा अपवाद को पकड़ने और उस ToString()पर करते हैं, क्योंकि यह अधिक त्रुटि विवरण कैप्चर करता है। मुझे लगता है कि आप include System.Linq;अपनी फ़ाइल के शीर्ष पर नहीं थे, लेकिन कौन जानता है? इसे अपने दम पर समझने की कोशिश करें, एक न्यूनतम प्रोटोटाइप बनाएं जो एक ही त्रुटि को प्रदर्शित करता है यदि आप नहीं कर सकते हैं और फिर एक प्रश्न में मदद मांग सकते हैं।

मैंने अभी ऊपर दिए गए कोड को कॉपी और पेस्ट किया है। उनमें से सभी ठीक काम करते हैं, केवल प्रेपेंड को छोड़कर जो मेरे द्वारा बताई गई त्रुटि है। यह एक रनटाइम अपवाद नहीं है इसका संकलन समय अपवाद है।
टिम न्यूटन

@ टिममन: मुझे नहीं पता कि आप जिस बारे में बात कर रहे हैं वह पूरी तरह से काम करता है जाहिर है कि आप गलत तरीके से एडिट में बदलाव को नजरअंदाज कर सकते हैं।

शायद यह हमारे पर्यावरण के बारे में कुछ अलग है। मैं VS2012 और .NET 4.5 का उपयोग कर रहा हूं। इस पर अब और समय बर्बाद मत करो, मैंने सोचा था कि मैं इंगित करूंगा कि उपरोक्त कोड के साथ एक समस्या है, एक छोटा सा। मैंने इस उत्तर को किसी भी तरह से उपयोगी माना है। धन्यवाद।
टिम न्यूटन

25

.Net Core में, एक विधि है Enumerable.Appendजो वास्तव में ऐसा करती है।

विधि का स्रोत कोड GitHub पर उपलब्ध है। .... कार्यान्वयन (अन्य उत्तरों में सुझावों की तुलना में अधिक परिष्कृत) एक नज़र के लायक है :)।


3
यह केवल कोर में ही नहीं है, फ्रेमवर्क 4.7.1 और नए: docs.microsoft.com/en-us/dotnet/api/…
sschoof


22

कोई IEnumerable इसमें आइटम जोड़ने का समर्थन नहीं करता है।

आप 'वैकल्पिक' है:

var List = new List(items);
List.Add(otherItem);

4
आपका सुझाव एकमात्र विकल्प नहीं है। उदाहरण के लिए, ICollection और IList दोनों ही यहाँ उचित विकल्प हैं।
जेसन

6
लेकिन आप या तो तुरंत नहीं कर सकते।
पॉल वैन ब्रेनक

16

दूसरा संदेश जोड़ने के लिए आपको -

IEnumerable<T> items = new T[]{new T("msg")};
items = items.Concat(new[] {new T("msg2")})

1
लेकिन आपको आइटम ऑब्जेक्ट को कॉनटैट विधि के परिणाम को निर्दिष्ट करने की भी आवश्यकता है।
टॉमाज़ प्रिज़िकोडज़की

1
हाँ, टॉमस आप सही हैं। मैंने अंतिम अभिव्यक्ति को आइटम के लिए संक्षिप्त मान निर्दिष्ट करने के लिए संशोधित किया है।
अनमोल

8

न केवल आप अपने राज्य की तरह आइटम नहीं जोड़ सकते हैं, लेकिन यदि आप एक आइटम को जोड़ते हैं List<T>(या बहुत अधिक किसी अन्य गैर-पढ़ा हुआ केवल संग्रह), जिसके लिए आपके पास एक मौजूदा गणनाकर्ता है, तो एन्यूमरेटर अमान्य है ( InvalidOperationExceptionतब से फेंकता है)।

यदि आप किसी प्रकार की डेटा क्वेरी से परिणाम एकत्रित कर रहे हैं, तो आप Concatएक्सटेंशन विधि का उपयोग कर सकते हैं :

संपादित करें: मैंने मूल रूप से Unionउदाहरण में विस्तार का उपयोग किया , जो वास्तव में सही नहीं है। मेरा आवेदन यह सुनिश्चित करने के लिए बड़े पैमाने पर उपयोग करता है कि ओवरलैपिंग प्रश्नों को डुप्लिकेट परिणाम न दें।

IEnumerable<T> itemsA = ...;
IEnumerable<T> itemsB = ...;
IEnumerable<T> itemsC = ...;
return itemsA.Concat(itemsB).Concat(itemsC);

8

मैं यहाँ यह कहने आया हूँ कि, Enumerable.Concatविस्तार विधि से अलग , Enumerable.Append.NET कोर १.१.१ में एक और विधि है । उत्तरार्द्ध आपको किसी एकल आइटम को किसी मौजूदा अनुक्रम में संक्षिप्त करने की अनुमति देता है। तो आमोल का जवाब भी लिखा जा सकता है

IEnumerable<T> items = new T[]{new T("msg")};
items = items.Append(new T("msg2"));

फिर भी, कृपया ध्यान दें कि यह फ़ंक्शन इनपुट अनुक्रम को नहीं बदलेगा, यह सिर्फ एक आवरण लौटाता है जो दिए गए अनुक्रम और एपेंड किए गए आइटम को एक साथ रखता है।


4

दूसरों ने पहले से ही इस बारे में बहुत स्पष्टीकरण दिया है कि आप (और नहीं!) में आइटम जोड़ने में सक्षम नहीं हो सकते हैं IEnumerable। मैं केवल यह जोड़ना चाहूंगा कि यदि आप एक इंटरफ़ेस का कोडिंग जारी रखना चाहते हैं जो संग्रह का प्रतिनिधित्व करता है और एक ऐड विधि चाहता है, तो आपको कोड करना चाहिए ICollectionया IList। एक अतिरिक्त बोनान्ज़ा के रूप में, ये इंटरफेस लागू होते हैं IEnumerable


1

तुम यह केर सकते हो।

//Create IEnumerable    
IEnumerable<T> items = new T[]{new T("msg")};

//Convert to list.
List<T> list = items.ToList();

//Add new item to list.
list.add(new T("msg2"));

//Cast list to IEnumerable
items = (IEnumerable<T>)items;

8
इस सवाल का जवाब 5 साल पहले अधिक पूर्ण फैशन में दिया गया था। किसी प्रश्न के अच्छे उत्तर के उदाहरण के रूप में स्वीकृत उत्तर को देखें।
pquest

1
अंतिम पंक्ति थी: आइटम = (IEnumerable <T>) सूची;
बेलन मार्टिन

0

ऐसा करने का सबसे आसान तरीका बस है

IEnumerable<T> items = new T[]{new T("msg")};
List<string> itemsList = new List<string>();
itemsList.AddRange(items.Select(y => y.ToString()));
itemsList.Add("msg2");

फिर आप IEnumerable के रूप में भी सूची वापस कर सकते हैं क्योंकि यह IEnumerable इंटरफ़ेस लागू करता है



-8

ज़रूर, आप कर सकते हैं (मैं अपना टी-व्यवसाय एक तरफ छोड़ रहा हूं):

public IEnumerable<string> tryAdd(IEnumerable<string> items)
{
    List<string> list = items.ToList();
    string obj = "";
    list.Add(obj);

    return list.Select(i => i);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.