जावास्क्रिप्ट कम () वस्तु पर


182

Array reduce()से एक मान प्राप्त करने के लिए अच्छा Array विधि है। उदाहरण:

[0,1,2,3,4].reduce(function(previousValue, currentValue, index, array){
  return previousValue + currentValue;
});

वस्तुओं के साथ समान हासिल करने का सबसे अच्छा तरीका क्या है? मैं यह करना चाहूंगा:

{ 
    a: {value:1}, 
    b: {value:2}, 
    c: {value:3} 
}.reduce(function(previous, current, index, array){
  return previous.value + current.value;
});

हालाँकि, ऑब्जेक्ट किसी भी reduce()विधि को लागू करने के लिए नहीं लगता है ।


1
क्या आप उपयोग कर रहे हैं Underscore.js?
सेथेन

नहीं। क्या अंडरस्कोर वस्तुओं के लिए कम प्रदान करता है?
पावेल एस।

मुझे याद नहीं आ रहा है। मुझे पता है कि इसकी एक reduceविधि है। मैं वहां जांच करूंगा। हालांकि, समाधान उतना मुश्किल नहीं लगता है।
सेथेन

1
@ सेथेन मालेनो, @ पावेल: हाँ में _वस्तुओं के लिए कमी है। सुनिश्चित नहीं है कि यह दुर्घटना से काम करता है या यदि ऑब्जेक्ट समर्थन जानबूझकर था, लेकिन वास्तव में आप इस प्रश्न के उदाहरण के रूप में ऑब्जेक्ट पास कर सकते हैं, और यह (वैचारिक रूप से) for..in, प्रत्येक कुंजी पर पाए गए मानों के साथ अपने इटेरेटर फ़ंक्शन को कॉल करेगा।
१०:१० पर रोहिन मार्थ

जवाबों:


55

आप वास्तव में इस मामले में क्या चाहते हैं Object.values। यहाँ एक संक्षिप्त ES6 कार्यान्वयन है जिसे ध्यान में रखते हुए:

const add = {
  a: {value:1},
  b: {value:2},
  c: {value:3}
}

const total = Object.values(add).reduce((t, {value}) => t + value, 0)

console.log(total) // 6

या केवल:

const add = {
  a: 1,
  b: 2,
  c: 3
}

const total = Object.values(add).reduce((t, n) => t + n)

console.log(total) // 6

यह Array.prototype.values ​​() है जिसे आपने अभी जोड़ा है - संपादित किया गया
जोनाथन वुड

281

एक विकल्प हो सकता है :reducekeys()

var o = { 
    a: {value:1}, 
    b: {value:2}, 
    c: {value:3} 
};

Object.keys(o).reduce(function (previous, key) {
    return previous + o[key].value;
}, 0);

इसके साथ, आप एक प्रारंभिक मान निर्दिष्ट करना चाहेंगे या पहला दौर होगा 'a' + 2

यदि आप परिणाम को ऑब्जेक्ट के रूप में चाहते हैं ( { value: ... }), तो आपको हर बार ऑब्जेक्ट को इनिशियलाइज़ और वापस करना होगा:

Object.keys(o).reduce(function (previous, key) {
    previous.value += o[key].value;
    return previous;
}, { value: 0 });

15
अच्छा जवाब है, लेकिन Object.keys के बजाय Object.values ​​का उपयोग करना अधिक पठनीय है क्योंकि हम यहां उन मूल्यों के बारे में चिंतित हैं जो कुंजियाँ नहीं हैं। यह इस तरह होना चाहिए: Object.values ​​(o) .reduce ((कुल, वर्तमान) => कुल + current.value, 0);
मीना ल्यूक

3
Object.values ​​में Object.keys की तुलना में बहुत बुरा ब्राउज़र समर्थन है, लेकिन यह एक मुद्दा नहीं हो सकता है यदि आप एक पॉलीफ़िल का उपयोग करते हैं या आप बैबल के साथ ट्रांसपाइल करते हैं
duhaime

वास्तव में, मैं इसे उन कुंजियों में इस्तेमाल कर रहा था, जिन्हें मोंगो मॉडल से पुनर्प्राप्त किया गया है, और मैंने कुंजियों को कम करने के परिणाम के लिए प्रारंभिक मूल्य के रूप में एक खाली वस्तु पारित की है, और जितना मैं @babel/plugin-proposal-object-rest-spreadप्लगइन का उपयोग कर रहा था , मैं संचयकर्ता मूल्य में फैल गया था कम करने की वापसी और यह एक आकर्षण की तरह काम करता है, लेकिन अगर मैं कुछ गलत कर रहा था, तो मैं भटक रहा था, क्योंकि मैं कम करने के प्रारंभिक मूल्य के लिए अप्रिय पारित कर रहा था और आपके जवाब ने मुझे साबित कर दिया कि मैंने सही काम किया!
a_m_dev

55

ES6 कार्यान्वयन: Object.entries ()

const o = {
  a: {value: 1},
  b: {value: 2},
  c: {value: 3}
};

const total = Object.entries(o).reduce(function (total, pair) {
  const [key, value] = pair;
  return total + value;
}, 0);

3
Object.entries(o); // returns [['value',1],['value',2],['value',3]]
faboulaws

1
const [कुंजी, मूल्य] = जोड़ी; मैंने यह कभी नहीं देखा!
मार्टिन मेसेर

9
@ मार्टिन-मेसेर - इसे विनाशकारी कहा जाता है। हम भी इस लाइन को बदल function (total, pair)सकते हैंfunction (total, [key, value])
जकूब ज़ाविलक

जबकि entriesइस ओवर को करने का एक साफ तरीका है keys, यह कम प्रदर्शन करने वाला है। hackernoon.com/…
लूट

@faboulaws Object.entries (o); // रिटर्न [["a", {value: 1}], ["b", {value: 2}], ["c", {value: 3}]]
थॉमस

19

सबसे पहले, आप काफी नहीं मिलता है जो पिछले मूल्य कम है।

आपके पास आपके पास छद्म कोड है return previous.value + current.value, इसलिए previousमूल्य अगले कॉल पर एक नंबर होगा, एक वस्तु नहीं।

दूसरा, reduceएक एरे विधि है, न कि किसी वस्तु का, और जब आप किसी वस्तु के गुणों का पुनरावृत्ति कर रहे हैं, तो आप उस आदेश पर भरोसा नहीं कर सकते (देखें: https://developer.mozilla.org/en-US/docs/ जावास्क्रिप्ट / संदर्भ / कथन / के लिए ... में , यह Object.keys पर भी लागू होता है); इसलिए मुझे यकीन नहीं है कि अगर reduceकिसी ऑब्जेक्ट पर आवेदन करना समझ में आता है।

हालांकि, यदि आदेश महत्वपूर्ण नहीं है, तो आपके पास हो सकता है:

Object.keys(obj).reduce(function(sum, key) {
    return sum + obj[key].value;
}, 0);

या आप बस वस्तु के मूल्य को मैप कर सकते हैं :

Object.keys(obj).map(function(key) { return this[key].value }, obj).reduce(function (previous, current) {
    return previous + current;
});

ES6 में PS वसा तीर फ़ंक्शन के सिंटैक्स के साथ (पहले से ही फ़ायरफ़ॉक्स नाइटली में), आप थोड़ा सिकुड़ सकते हैं:

Object.keys(obj).map(key => obj[key].value).reduce((previous, current) => previous + current);

3

1:

[{value:5}, {value:10}].reduce((previousValue, currentValue) => { return {value: previousValue.value + currentValue.value}})

>> Object {value: 15}

2:

[{value:5}, {value:10}].map(item => item.value).reduce((previousValue, currentValue) => {return previousValue + currentValue })

>> 15

3:

[{value:5}, {value:10}].reduce(function (previousValue, currentValue) {
      return {value: previousValue.value + currentValue.value};
})

>> Object {value: 15}

2

Object.prototype बढ़ाएँ।

Object.prototype.reduce = function( reduceCallback, initialValue ) {
    var obj = this, keys = Object.keys( obj );

    return keys.reduce( function( prevVal, item, idx, arr ) {
        return reduceCallback( prevVal, item, obj[item], obj );
    }, initialValue );
};

उपयोग का नमूना।

var dataset = {
    key1 : 'value1',
    key2 : 'value2',
    key3 : 'value3'
};

function reduceFn( prevVal, key, val, obj ) {
    return prevVal + key + ' : ' + val + '; ';
}

console.log( dataset.reduce( reduceFn, 'initialValue' ) );
'Output' == 'initialValue; key1 : value1; key2 : value2; key3 : value3; '.

यह, दोस्तों! ;-)


-1, अब आपके पास भविष्य की सभी वस्तुओं पर एक नई संपत्ति है: jsfiddle.net/ygonjooh
जोहान


1
कृपया इस तरह आधार प्रोटोटाइप को संशोधित न करें। यह भविष्य के डेवलपर्स के लिए एक ही कोड बेस में काम करने के लिए बहुत सारी समस्याएं पैदा कर सकता है
adam.k

हां, यह एक "बंदर पैचिंग" है यह समाधान 6 साल पहले लिखा गया था और अभी भी प्रासंगिक नहीं है, बस ध्यान रखें और उदाहरण के लिए, Object.entries()2021 में उपयोग करना बेहतर होगा
user1247458

2

आप एक जनरेटर अभिव्यक्ति का उपयोग कर सकते हैं (अब और वर्षों के लिए सभी ब्राउज़रों में समर्थित है)

>>> a = {"b": 3}
Object { b=3}

>>> [[i, a[i]] for (i in a) if (a.hasOwnProperty(i))]
[["b", 3]]

2

ऑब्जेक्ट को एक सरणी में बदल दिया जा सकता है: Object.entries () , Object.keys () , Object.values ​​() , और फिर सरणी के रूप में कम किया जा सकता है। लेकिन आप मध्यवर्ती सरणी बनाए बिना किसी ऑब्जेक्ट को कम भी कर सकते हैं।

मैंने वस्तुओं के साथ काम करने के लिए थोड़ा सहायक पुस्तकालय का निर्माण किया है।

npm install --save odict

यह reduceफ़ंक्शन है जो Array.prototype.reduce () की तरह बहुत काम करता है :

export const reduce = (dict, reducer, accumulator) => {
  for (const key in dict)
    accumulator = reducer(accumulator, dict[key], key, dict);
  return accumulator;
};

आप इसे भी असाइन कर सकते हैं:

Object.reduce = reduce;

के रूप में इस विधि बहुत उपयोगी है!

तो आपके प्रश्न का उत्तर होगा:

const result = Object.reduce(
  {
    a: {value:1},
    b: {value:2},
    c: {value:3},
  },
  (accumulator, current) => (accumulator.value += current.value, accumulator), // reducer function must return accumulator
  {value: 0} // initial accumulator value
);

1

यदि आप एक सरणी का उपयोग कर सकते हैं, तो एक सरणी का उपयोग करें, एक सरणी की लंबाई और क्रम इसके लायक आधे हैं।

function reducer(obj, fun, temp){
    if(typeof fun=== 'function'){
        if(temp== undefined) temp= '';
        for(var p in obj){
            if(obj.hasOwnProperty(p)){
                temp= fun(obj[p], temp, p, obj);
            }
        }
    }
    return temp;
}
var O={a:{value:1},b:{value:2},c:{value:3}}

reducer(O, function(a, b){return a.value+b;},0);

/ * लौटाया गया मान: (संख्या) 6 * /


1

यह अपने आप को लागू करने के लिए बहुत मुश्किल नहीं है:

function reduceObj(obj, callback, initial) {
    "use strict";
    var key, lastvalue, firstIteration = true;
    if (typeof callback !== 'function') {
        throw new TypeError(callback + 'is not a function');
    }   
    if (arguments.length > 2) {
        // initial value set
        firstIteration = false;
        lastvalue = initial;
    }
    for (key in obj) {
        if (!obj.hasOwnProperty(key)) continue;
        if (firstIteration)
            firstIteration = false;
            lastvalue = obj[key];
            continue;
        }
        lastvalue = callback(lastvalue, obj[key], key, obj);
    }
    if (firstIteration) {
        throw new TypeError('Reduce of empty object with no initial value');
    }
    return lastvalue;
}

कार्रवाई में:

var o = {a: {value:1}, b: {value:2}, c: {value:3}};
reduceObj(o, function(prev, curr) { prev.value += cur.value; return prev;}, {value:0});
reduceObj(o, function(prev, curr) { return {value: prev.value + curr.value};});
// both == { value: 6 };

reduceObj(o, function(prev, curr) { return prev + curr.value; }, 0);
// == 6

आप इसे ऑब्जेक्ट प्रोटोटाइप में भी जोड़ सकते हैं:

if (typeof Object.prototype.reduce !== 'function') {
    Object.prototype.reduce = function(callback, initial) {
        "use strict";
        var args = Array.prototype.slice(arguments);
        args.unshift(this);
        return reduceObj.apply(null, args);
    }
}

0

चूंकि यह वास्तव में अभी तक एक जवाब में पुष्टि नहीं की गई है, अंडरस्कोर reduceभी इसके लिए काम करता है।

_.reduce({ 
    a: {value:1}, 
    b: {value:2}, 
    c: {value:3} 
}, function(prev, current){
    //prev is either first object or total value
    var total = prev.value || prev

    return total + current.value
})

ध्यान दें, _.reduceइटरेटर फ़ंक्शन को कॉल किए बिना सूची ऑब्जेक्ट में केवल एक आइटम होने पर एकमात्र मान (ऑब्जेक्ट या अन्यथा) वापस कर देगा।

_.reduce({ 
    a: {value:1} 
}, function(prev, current){
    //not called
})

//returns {value: 1} instead of 1

"इस अन्य पुस्तकालय का प्रयास करें" उपयोगी नहीं है
ग्रुओन शैफ्टो

आपके लिए उपयोगी नहीं है
क्रिस डॉल्फिन

0

इस एक लाइनर एरो फंक्शन को आज़माएं

Object.values(o).map(a => a.value, o).reduce((ac, key, index, arr) => ac+=key)

0

इसको आजमाओ। यह अन्य चर से संख्याओं को क्रमबद्ध करेगा।

const obj = {
   a: 1,
   b: 2,
   c: 3
};
const result = Object.keys(obj)
.reduce((acc, rec) => typeof obj[rec] === "number" ? acc.concat([obj[rec]]) : acc, [])
.reduce((acc, rec) => acc + rec)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.