ImmutableJS के साथ सूची के अंदर तत्व को कैसे अपडेट करें?


129

यहाँ आधिकारिक डॉक्स ने कहा है

updateIn(keyPath: Array<any>, updater: (value: any) => any): List<T>
updateIn(keyPath: Array<any>, notSetValue: any, updater: (value: any) => any): List<T>
updateIn(keyPath: Iterable<any, any>, updater: (value: any) => any): List<T>
updateIn(keyPath: Iterable<any, any>, notSetValue: any, updater: (value: any) => any): List<T>

कोई रास्ता नहीं है सामान्य वेब डेवलपर (कार्यात्मक प्रोग्रामर नहीं) यह समझ जाएगा!

मेरे पास बहुत सरल (गैर-कार्यात्मक दृष्टिकोण के लिए) मामला है।

var arr = [];
arr.push({id: 1, name: "first", count: 2});
arr.push({id: 2, name: "second", count: 1});
arr.push({id: 3, name: "third", count: 2});
arr.push({id: 4, name: "fourth", count: 1});
var list = Immutable.List.of(arr);

मैं कैसे कर सकते हैं listजहां नाम के साथ तत्व तीसरे इसकी राशि गिनती करने के लिए सेट 4 ?


43
मुझे नहीं पता कि यह कैसा दिखता है, लेकिन प्रलेखन भयानक है facebook.github.io/immutable-js/docs/#/List/update
Vitalii Korsakov

71
प्रलेखन पर खुदाई के लिए गंभीर उत्थान। अगर उस वाक्य रचना का लक्ष्य मुझे गूंगा / अपर्याप्त महसूस करना है, तो निश्चित सफलता। यदि लक्ष्य, हालांकि, यह बताने के लिए है कि कैसे काम करने योग्य है, अच्छी तरह से ...
ओवेन

9
मुझे सहमत होना पड़ता है, मैं अपरिवर्तनीय के लिए प्रलेखन ढूंढता हूं। जेएस को गंभीरता से निराशा होती है। इसके लिए स्वीकृत समाधान एक विधि findIndex () का उपयोग करता है जिसे मैं डॉक्स में बिल्कुल भी नहीं देखता हूं।
रिचर्डफोरर

3
इसके बजाय वे उन चीजों के बजाय प्रत्येक फ़ंक्शन के लिए एक उदाहरण देते हैं।
RedGiant 15

4
माना। दस्तावेज को किसी वैज्ञानिक ने बुलबुले में लिखा होगा, न कि किसी ऐसे व्यक्ति द्वारा, जो कुछ सरल उदाहरण दिखाना चाहता है। डॉक्यूमेंटेशन के लिए कुछ डॉक्यूमेंटेशन की जरूरत होती है। उदाहरण के लिए, मुझे अंडरस्कोर प्रलेखन पसंद है, व्यावहारिक उदाहरणों को देखने के लिए बहुत आसान है।
ReduxDJ

जवाबों:


119

सबसे उपयुक्त मामला दोनों findIndexऔर updateविधियों का उपयोग करना है ।

list = list.update(
  list.findIndex(function(item) { 
    return item.get("name") === "third"; 
  }), function(item) {
    return item.set("count", 4);
  }
); 

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


1
यदि आपको डुप्लिकेट नामों की आवश्यकता है, तो मानों के रूप में मल्टीपैप - या टुपल्स वाले नक्शे का उपयोग करें।
बेर्गी

5
क्या यह अनजाने में सूची के अंतिम तत्व को अपडेट नहीं करेगा यदि नाम के रूप में "तीन" के साथ कोई तत्व नहीं है? उस स्थिति में findIndex () -1 लौट आएगा, जो अंतिम तत्व के सूचकांक के रूप में अद्यतन () व्याख्या करेगा।
सैम स्ट्रॉ

1
नहीं है, -1 नहीं पिछले तत्व है
विटाली Korsakov

9
@ सलाम सही है। डॉक्स से: "इंडेक्स एक ऋणात्मक संख्या हो सकती है, जो सूची के अंत से वापस इंडेक्स करता है। v.update (-1) सूची में अंतिम आइटम को अपडेट करता है।" facebook.github.io/immutable-js/docs/#/List/update
Gabriel Ferraz

1
मैं item.set को कॉल नहीं कर सका क्योंकि मेरे लिए आइटम अपरिवर्तनीय प्रकार नहीं था, मुझे आइटम को पहले मैप करना था, कॉल सेट करना था और फिर इसे फिर से ऑब्जेक्ट में बदलना होगा। तो इस उदाहरण के लिए, फ़ंक्शन (आइटम) {रिटर्न मैप (आइटम) ।सेट ("गिनती", 4) .toObject (); }
syclee

36

साथ .setIn () आप एक ही कर सकते हैं:

let obj = fromJS({
  elem: [
    {id: 1, name: "first", count: 2},
    {id: 2, name: "second", count: 1},
    {id: 3, name: "third", count: 2},
    {id: 4, name: "fourth", count: 1}
  ]
});

obj = obj.setIn(['elem', 3, 'count'], 4);

यदि हम उस प्रविष्टि के सूचकांक को नहीं जानते हैं जिसे हम अद्यतन करना चाहते हैं। .FindIndex () का उपयोग करके इसे ढूंढना बहुत आसान है :

const indexOfListToUpdate = obj.get('elem').findIndex(listItem => {
  return listItem.get('name') === 'third';
});
obj = obj.setIn(['elem', indexOfListingToUpdate, 'count'], 4);

आशा करता हूँ की ये काम करेगा!


1
आप { }अंदर याद कर रहे हैं fromJS( ), ब्रेसिज़ के बिना यह वैध जेएस नहीं है।
एंडी

1
मैं लौटी हुई वस्तु को 'गिरफ्तार' नहीं कहूंगा क्योंकि यह एक वस्तु है। केवल arr.elem एक सरणी है
Nir O.

21
var index = list.findIndex(item => item.name === "three")
list = list.setIn([index, "count"], 4)

व्याख्या

Immutable.js संग्रह को अपडेट करना हमेशा उन संग्रहों के नए संस्करणों को मूल अपरिवर्तित छोड़ देता है। उसके कारण, हम JavaScript के list[2].count = 4म्यूटेशन सिंटैक्स का उपयोग नहीं कर सकते हैं । इसके बजाय हमें विधियों को कॉल करने की आवश्यकता है, जैसे हम जावा संग्रह कक्षाओं के साथ कर सकते हैं।

आइए एक सरल उदाहरण से शुरू करते हैं: एक सूची में सिर्फ मायने रखता है।

var arr = [];
arr.push(2);
arr.push(1);
arr.push(2);
arr.push(1);
var counts = Immutable.List.of(arr);

अब अगर हम 3rd आइटम को अपडेट करना चाहते हैं, तो एक प्लेन JS सरणी दिख सकती है counts[2] = 4:। चूंकि हम म्यूटेशन का उपयोग नहीं कर सकते हैं, और हमें कॉल करने की आवश्यकता है, इसके बजाय हम उपयोग कर सकते हैं: counts.set(2, 4)- इसका मतलब है कि 4इंडेक्स पर मान सेट करें 2

गहरा अद्यतन

आपके द्वारा दिए गए उदाहरण में नेस्टेड डेटा है। हम अभी set()शुरुआती संग्रह पर उपयोग नहीं कर सकते ।

Immutable.js संग्रह में "इन" के साथ समाप्त होने वाले नामों के साथ तरीकों का एक परिवार है जो आपको एक नेस्टेड सेट में गहरे बदलाव करने की अनुमति देता है। अधिकांश सामान्य अद्यतन विधियों में एक संबंधित "इन" विधि है। उदाहरण के लिए setवहाँ है setIn। सूचकांक या एक कुंजी को पहले तर्क के रूप में स्वीकार करने के बजाय, ये "इन" तरीके "कुंजी पथ" को स्वीकार करते हैं। मुख्य पथ अनुक्रमणिका या कुंजियों का एक सरणी है जो दिखाता है कि आप जिस मूल्य को अपडेट करना चाहते हैं उसे कैसे प्राप्त करें।

अपने उदाहरण में, आप सूची 2 में सूची में आइटम को अद्यतन करना चाहते थे, और फिर उस आइटम के भीतर कुंजी "गणना" पर मूल्य। तो प्रमुख मार्ग होगा [2, "count"]setInविधि का दूसरा पैरामीटर उसी तरह काम करता है set, यह नया मूल्य है जिसे हम वहां रखना चाहते हैं, इसलिए:

list = list.setIn([2, "count"], 4)

सही कुंजी पथ ढूँढना

एक कदम आगे बढ़ते हुए, आपने वास्तव में कहा था कि आप उस आइटम को अपडेट करना चाहते हैं जहां नाम "तीन" है जो सिर्फ 3 आइटम से अलग है। उदाहरण के लिए, शायद आपकी सूची को क्रमबद्ध नहीं किया गया है, या शायद "दो" नामक आइटम को पहले हटा दिया गया था? इसका मतलब है कि पहले हमें यह सुनिश्चित करने की आवश्यकता है कि हम वास्तव में सही मुख्य मार्ग को जानते हैं! इसके लिए हम findIndex()विधि का उपयोग कर सकते हैं (जो, वैसे, लगभग Array # findIndex की तरह काम करता है )।

एक बार जब हम उस सूची में सूची पा लेते हैं जिसमें वह आइटम है जिसे हम अपडेट करना चाहते हैं, तो हम उस मान को मुख्य पथ प्रदान कर सकते हैं जिसे हम अपडेट करना चाहते हैं:

var index = list.findIndex(item => item.name === "three")
list = list.setIn([index, "count"], 4)

एनबी: SetबनामUpdate

मूल प्रश्न सेट विधियों के बजाय अद्यतन विधियों का उल्लेख करता है। मैं उस फ़ंक्शन में दूसरे तर्क की व्याख्या करता हूं (कहा जाता है updater), क्योंकि यह अलग है set()। जबकि दूसरा तर्क set()वह नया मूल्य है जो हम चाहते हैं, दूसरा तर्क update()एक फ़ंक्शन है जो पिछले मूल्य को स्वीकार करता है और हम जो नया मूल्य चाहते हैं उसे वापस करते हैं। फिर, updateIn()"इन" भिन्नता है update()जिसमें से एक प्रमुख मार्ग को स्वीकार करता है।

उदाहरण के लिए कहें कि हम आपके उदाहरण की एक भिन्नता चाहते थे जो गिनती को केवल निर्धारित नहीं करता था 4, बल्कि मौजूदा गणना को बढ़ाता है, हम एक फ़ंक्शन प्रदान कर सकते हैं जो मौजूदा मूल्य में एक जोड़ता है:

var index = list.findIndex(item => item.name === "three")
list = list.updateIn([index, "count"], value => value + 1)

19

यहाँ क्या आधिकारिक डॉक्स ने कहा है ... updateIn

आप की जरूरत नहीं है updateIn, जो केवल नेस्टेड संरचनाओं के लिए है। आप उस updateविधि की तलाश कर रहे हैं , जिसमें बहुत सरल हस्ताक्षर और दस्तावेज हैं:

इंडेक्स में एक अद्यतन मूल्य के साथ एक नई सूची लौटाता है, जिसमें मौजूदा मूल्य के साथ अपडेटर को कॉल करने का रिटर्न वैल्यू, या इंडेक्स सेट नहीं होने पर NotSetValue।

update(index: number, updater: (value: T) => T): List<T>
update(index: number, notSetValue: T, updater: (value: T) => T): List<T>

जो, के रूप में Map::updateकिए गए दस्तावेज़ों का सुझाव है, " के बराबर:list.set(index, updater(list.get(index, notSetValue))) "।

"तीसरा" नाम वाला तत्व

ऐसा नहीं है कि सूची कैसे काम करती है। आपको उस तत्व के सूचकांक को जानना होगा जिसे आप अपडेट करना चाहते हैं, या आपको उसे खोजना होगा।

मैं सूची को कैसे अपडेट कर सकता हूं जहां तीसरे नाम वाले तत्व की गिनती 4 पर सेट है?

यह करना चाहिए:

list = list.update(2, function(v) {
    return {id: v.id, name: v.name, count: 4};
});

14
नहीं, डेटा संरचना की आपकी पसंद व्यावसायिक तर्क को संतुष्ट नहीं करती है :-) यदि आप तत्वों को उनके नाम से एक्सेस करना चाहते हैं, तो आपको सूची के बजाय मानचित्र का उपयोग करना चाहिए।
बर्गी

1
@बर्गी, सच में? तो अगर मेरे पास है, कहते हैं, एक कक्षा में छात्रों की एक सूची है, और मैं का उपयोग कर एक इस छात्र डेटा पर CRUD संचालन करना चाहते हैं, Mapएक से अधिक Listदृष्टिकोण आप सुझाव है कि है? या आप केवल इतना ही कहते हैं क्योंकि ओपी ने कहा "नाम से आइटम का चयन करें" और "आईडी द्वारा आइटम का चयन न करें"?
डेविड गिल्बर्टसन

2
@DavidGilbertson: CRUD? मैं एक डेटाबेस का सुझाव देता हूं :-) लेकिन हां, एक आईडी-> छात्र का नक्शा एक सूची की तुलना में अधिक उपयुक्त लगता है, जब तक कि आपको उन पर कोई आदेश नहीं मिला है और उन्हें सूचकांक द्वारा चुनना चाहते हैं।
बरगी

1
@बर्गी मुझे लगता है कि हम असहमत होने के लिए सहमत होंगे, मुझे आईडी के साथ चीजों के सरणियों के रूप में एपीआई से बहुत सारे डेटा वापस मिलेंगे, जहां मुझे आईडी द्वारा उन चीजों को अपडेट करने की आवश्यकता है। यह एक जेएस सरणी है, और मेरे दिमाग में, इसलिए एक अपरिवर्तनीय जेएस सूची होनी चाहिए।
डेविड गिल्बर्टसन

1
@DavidGilbertson: मुझे लगता है कि वे API सेट के लिए JSON एरेज़ लेते हैं - जो स्पष्ट रूप से अनियंत्रित हैं।
बरगी

12

.Map () का प्रयोग करें

list = list.map(item => 
   item.get("name") === "third" ? item.set("count", 4) : item
);

var arr = [];
arr.push({id: 1, name: "first", count: 2});
arr.push({id: 2, name: "second", count: 1});
arr.push({id: 3, name: "third", count: 2});
arr.push({id: 4, name: "fourth", count: 1});
var list = Immutable.fromJS(arr);

var newList = list.map(function(item) {
    if(item.get("name") === "third") {
      return item.set("count", 4);
    } else {
      return item;
    }
});

console.log('newList', newList.toJS());

// More succinctly, using ES2015:
var newList2 = list.map(item => 
    item.get("name") === "third" ? item.set("count", 4) : item
);

console.log('newList2', newList2.toJS());
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script>


1
इसके लिए धन्यवाद - इतने सारे भयानक उत्तर यहां दिए गए हैं, असली जवाब "यदि आप सूची बदलना चाहते हैं, तो मानचित्र का उपयोग करें"। यह लगातार अपरिवर्तनीय डेटा संरचनाओं का संपूर्ण बिंदु है, आप उन्हें "अपडेट" नहीं करते हैं, आप इसमें अद्यतन मूल्यों के साथ एक नई संरचना बनाते हैं; और ऐसा करना सस्ता है क्योंकि अनधिकृत सूची तत्वों को साझा किया जाता है।
कोर्न

2

मैं वास्तव में thomastuts वेबसाइट से इस दृष्टिकोण को पसंद करता हूं :

const book = fromJS({
  title: 'Harry Potter & The Goblet of Fire',
  isbn: '0439139600',
  series: 'Harry Potter',
  author: {
    firstName: 'J.K.',
    lastName: 'Rowling'
  },
  genres: [
    'Crime',
    'Fiction',
    'Adventure',
  ],
  storeListings: [
    {storeId: 'amazon', price: 7.95},
    {storeId: 'barnesnoble', price: 7.95},
    {storeId: 'biblio', price: 4.99},
    {storeId: 'bookdepository', price: 11.88},
  ]
});

const indexOfListingToUpdate = book.get('storeListings').findIndex(listing => {
  return listing.get('storeId') === 'amazon';
});

const updatedBookState = book.setIn(['storeListings', indexOfListingToUpdate, 'price'], 6.80);

return state.set('book', updatedBookState);

-2

आप उपयोग कर सकते हैं map:

list = list.map((item) => { 
    return item.get("name") === "third" ? item.set("count", 4) : item; 
});

लेकिन यह पूरे संग्रह पर पुनरावृति करेगा।

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