2010-10-19 9 views
7

मेरे पास शब्दकोश है जो आबादी वाला है और मेरा कोई नियंत्रण नहीं है।शब्दकोश संशोधित करें मूल्य संभव है। सही दृष्टिकोण क्या है?

मुझे मूल्य संशोधित करने की आवश्यकता है कि मैं यह कैसे कर सकता हूं?

मैं एक Noddy उदाहरण डाल दिया है एक साथ समस्या

class Program 
{ 
    static void Main(string[] args) 
    { 


     Dictionary<Customer, int> CustomerOrderDictionary = new Dictionary<Customer, int>(); 

     CustomerOrderDictionary.Add(new Customer { Id = 1, FullName = "Jo Bloogs" },3); 

     CustomerOrderDictionary.Add(new Customer { Id = 2, FullName = "Rob Smith" },5); 

     //now I decide to increase the quantity but cannot do the below as value has no setter 

     foreach (var pair in CustomerOrderDictionary) 
     { 
      if(pair.Key.Id==1) 
      { 
       pair.Value = 4;///ERROR HERE 
      } 
     } 
    } 
} 


public class Customer 
{ 
    public int Id { get; set; } 
    public string FullName { get; set; } 
} 

कोई सुझाव व्याख्या करने के लिए? बहुत बहुत धन्यवाद

उत्तर

8

मैं सुझाव है कि आप बाहर काम जो कुंजी पहले को संशोधित करने की जरूरत है, और फिर उन संशोधनों से अधिक पुनरावृति। अन्यथा आप इसे संग्रहित करते समय संग्रह को संशोधित कर देंगे, जो अपवाद फेंक देगा। उदाहरण के लिए:

// The ToList() call here is important, so that we evaluate all of the query 
// *before* we start modifying the dictionary 
var keysToModify = CustomerOrderDictionary.Keys 
              .Where(k => k.Id == 1) 
              .ToList(); 
foreach (var key in keysToModify) 
{ 
    CustomerOrderDictionary[key] = 4; 
} 
+0

हाय, धन्यवाद बहुत काम करता है। मैं यह देखने की कोशिश करूंगा कि यह वास्तविक कोड के साथ काम करता है। धन्यवाद – user9969

6

समस्या यह है कि जोड़ी KeyValuePair पर टाइप की गई है जो एक पठनीय वस्तु है और इसे संशोधित नहीं किया जा सकता है। इसके अतिरिक्त KeyValuePair संग्रह शब्दकोश की सामग्री को देखने का एक तरीका है (इसे बदल नहीं रहा है)।

आप यहां क्या करना चाहते हैं बस सीधे शब्दकोश को संशोधित करें। KeyKeyValuePair में शब्दकोश में उसी प्रविष्टि को अपडेट करने के लिए उपयोग किया जा सकता है।

if(pair.Key.Id==1) { 
    CustomerOrderDictionary[pair.Key] = 4; 
} 

संपादित

के रूप में जॉन ने बताया असाइनमेंट इटरेटर अमान्य हो जाएगा। सबसे सरल, लेकिन असुरक्षित मार्ग, लूप की शुरुआत में गणनाकर्ता की प्रतिलिपि बनाना है।

CustomerOrderDictionary[new Customer { Id = 1, FullName = "Jo Bloogs" }]=4 

सूचना है कि "1" अपने शब्दकोश में एक महत्वपूर्ण नहीं है:

foreach (var pair in CustomerOrderDictionary.ToList()) 
+2

सिवाय जो शब्दकोश को संशोधित करता है इटरेटर को मान्य करता है :( –

+0

हाय, आपके उत्तर के लिए धन्यवाद। काम नहीं करने की कोशिश की। क्या आप ऊपर एक लूप में डाल रहे हैं? अगर नहीं जोड़ी है? मूर्खतापूर्ण होने के लिए खेद है – user9969

+0

@ जोन ओह, हाँ, उस हिस्से के बारे में भूल गए। – JaredPar

0
foreach (Customer customer in customers.Keys) 
{ 
    if (customer.Id == 1) 
     customers[ customer ] = 4; 
} 
0
CustomerOrderDictionary[1] = 4; 
+0

यह गलत है, शब्दकोश की कुंजी int int नहीं है (मेरा उत्तर देखें ..) –

0

यहाँ एक तरीका है कि ऐसा करने के लिए (सिर्फ एक मूल्य के हिस्सा बताए ..) है। Customer है, इसलिए आपको इसका उपयोग करना होगा।

सूचना भी है कि CustomerIEquatable को लागू करना चाहिए के रूप में समझाया here

0

ठीक है, अपने उदाहरण में आप प्रभावी रूप से बस के साथ Id = 1 Customer वस्तु के लिए प्रवेश पता लगा रहे हैं और संबद्ध मूल्य को अद्यतन करने। प्रैक्टिस में, मुझे लगता है कि आपका कोड शब्दकोश में संबंधित मान को अपडेट करने से पहले आपके इच्छित Customer ऑब्जेक्ट का संदर्भ प्राप्त करने में सक्षम होगा। यदि ऐसा है, तो लूप की कोई आवश्यकता नहीं है।

नीचे एक बहुत ही सरल उदाहरण है जहां एक लूप की आवश्यकता नहीं है क्योंकि आपके कोड में पहले से ही customer1 चर का संदर्भ है। जबकि मेरा उदाहरण अत्यधिक सरलीकृत है, अवधारणा यह है कि आप संभवतः अपने वांछित Customer ऑब्जेक्ट को संदर्भित करने के अलावा कुछ अन्य माध्यमों के माध्यम से संदर्भ प्राप्त कर सकते हैं।

static void Main(string[] args) 
    { 
     Dictionary<Customer, int> CustomerOrderDictionary = new Dictionary<Customer, int>(); 

     Customer customer1 = new Customer { Id = 1, FullName = "Jo Bloogs" }; 
     Customer customer2 = new Customer { Id = 2, FullName = "Rob Smith" }; 

     CustomerOrderDictionary.Add(customer1, 3); 

     CustomerOrderDictionary.Add(customer2, 5); 

     // you already have a reference to customer1, so just use the accessor on the dictionary to update the value 
     CustomerOrderDictionary[customer1]++; 
    } 

आप कुछ अन्य मानदंडों के आधार पर Customer वस्तुओं एकाधिक पर अद्यतन किसी तरह का प्रदर्शन करने के लिए की जरूरत है, तो आप एक पाश आवश्यकता हो सकती है। निम्नलिखित उदाहरण मानते हैं कि आपके पास Customer ऑब्जेक्ट्स को संग्रहीत करने वाले शब्दकोश के अलावा कुछ संग्रह होगा, और आप Customer ऑब्जेक्ट्स के उस संग्रह का उपयोग कर सकते हैं, जिनकी पहचान करने के लिए शब्दकोश में संबंधित मूल्य को अपडेट किया जाना चाहिए।

static void Main(string[] args) 
    { 
     // presumably you will have a separate collection of all your Customer objects somewhere 
     List<Customer> customers = new List<Customer>(); 

     Customer customer1 = new Customer { Id = 1, FullName = "Jo Bloogs" }; 
     Customer customer2 = new Customer { Id = 2, FullName = "Rob Smith" }; 
     Customer customer3 = new Customer { Id = 3, FullName = "Rob Zombie" }; 

     customers.Add(customer1); 
     customers.Add(customer2); 
     customers.Add(customer3); 

     Dictionary<Customer, int> CustomerOrderDictionary = new Dictionary<Customer, int>(); 

     CustomerOrderDictionary.Add(customer1, 3); 
     CustomerOrderDictionary.Add(customer2, 5); 

     // let's just say that we're going to update the value for any customers whose name starts with "Rob" 
     // use the separate list of Customer objects for the iteration, 
     // because you would not be allowed to modify the dictionary if you iterate over the dictionary directly 
     foreach (var customer in customers.Where(c => c.FullName.StartsWith("Rob"))) 
     { 
      // the dictionary may or may not contain an entry for every Customer in the list, so use TryGetValue 
      int value; 
      if (CustomerOrderDictionary.TryGetValue(customer, out value)) 
       // if an entry is found for this customer, then increment the value of that entry by 1 
       CustomerOrderDictionary[customer] = value + 1; 
      else 
       // if there is no entry in the dictionary for this Customer, let's add one just for the heck of it 
       CustomerOrderDictionary.Add(customer, 1); 
     } 
    } 

यदि यह स्थिति और Customer वस्तुओं है कि आप उपलब्ध है का एकमात्र स्रोत नहीं है शब्दकोश में ही है, तो आप एक अलग सूची के लिए बाहर उन वस्तुओं की क्लोनिंग/नकल किसी तरह का प्रदर्शन करने के लिए की आवश्यकता होगी संशोधन के लिए शब्दकोश पर पुनरावृत्त करने से पहले/सरणी। इस मामले के लिए जॉन स्कीट का जवाब देखें; वह फ़िल्टर का उपयोग Keys संपत्ति पर फ़िल्टर करने का सुझाव देता है और पुनरावृत्ति के उद्देश्य के लिए अलग List<Customer> उदाहरण बनाने के लिए ToList विधि का उपयोग करता है।

1

यहाँ एक वैकल्पिक दृष्टिकोण

1) एक नया वर्ग

// wrapper class to allow me to edit a dictionary 
public class IntWrapper 
{ 
    public int OrderCount{ get; set; } 
} 

2 बनाएं) बदलें इस घोषणा

Dictionary<Customer, IntWrapper> CustomerOrderDictionary = new Dictionary<Customer, IntWrapper>(); 

3) निरुपित है अपने चर

pair.Value.OrderCount = 4; 
+0

नकारात्मक वोट क्यों? यह मेरे लिए काम करता है ... रचनात्मक फीडबैक की सराहना की जाती है – LamonteCristo

+0

मैं विशेष रूप से 'int' को लपेटने के लिए कक्षा को परिभाषित करने के बजाय, एक एकल' वैल्यू 'फ़ील्ड के साथ एक सामान्य' धारक 'परिभाषित करता हूं। साथ ही, आप यह दिखाने के लिए भूल गए कि शब्दकोश में नए रैपर को कैसे जोड़ा जाना चाहिए। – supercat

+0

एक लाभ जो उल्लेखनीय हो सकता है वह यह है कि जब फ्री-मल्टी-थ्रेडेड परिदृश्यों में उपयोग किया जाता है, तो आप शब्दकोश को संरक्षित करने के लिए 'रीडरवाइटर लॉकस्लिम' का उपयोग कर सकते हैं, और जब आप स्वयं को शब्दकोश बदलते हैं तो केवल 'राइटर' लॉक प्राप्त करना होता है। किसी आइटम के साथ काम करते समय, आप आइटम पर लॉक प्राप्त करना चाहते हैं, लेकिन इससे शब्दकोश में दूसरों की पहुंच में हस्तक्षेप नहीं होगा। – supercat

संबंधित मुद्दे