객체의 자바 스크립트 reduce ()


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;
});

그러나 Object에는 reduce()메서드가 구현 되지 않은 것 같습니다 .


1
사용하고 Underscore.js있습니까?
Sethen

아니. Underscore는 객체 축소를 제공합니까?
Pavel S.

기억이 안나 reduce방법 이 있다는 것을 알고 있습니다 . 나는 거기에서 확인할 것이다. 그러나 해결책은 그렇게 어렵지 않습니다.
Sethen

1
@Sethen Maleno, @Pavel : yes _는 객체를 줄입니다. 우연히 작동하는지 또는 객체 지원이 의도적인지 확실하지 않지만 실제로이 질문의 예에서와 같이 객체를 전달할 for..in수 있으며 각 개념 키에서 찾은 값으로 반복기 함수를 호출합니다 (개념적으로) .
Roatin Marth

답변:


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 ​​()입니다. – 지금 수정
Jonathan Wood

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.

결과를 Object ( { 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 ((total, current) => total + current.value, 0);
Mina Luke

3
Object.values는 Object.keys보다 훨씬 더 브라우저 지원이 있지만, 당신은 polyfill을 사용하는 경우 그 문제가되지 않았거나 바벨에 transpile
duhaime

정확히, 나는 mongo 모델에서 검색 한 비트에서 이것을 사용하고 있었고 키를 줄인 결과에 빈 값을 초기 값으로 전달했으며 @babel/plugin-proposal-object-rest-spreadplugin 을 사용 하는 한 누적 값을 감소의 반환과 매력처럼 작동하지만, 내가 뭔가 잘못하고 있는지, 나는 내가 obejct를 감소의 초기 값으로 전달하고 있고 대답이 내가 옳은 일을했다는 것을 증명했기 때문에 궁금했습니다!
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 [키, 값] = 쌍; 나는 이것을 본 적이 없다!
Martin Meeser

9
@ martin-meeser-이것을 파괴라고합니다. 우리는 심지어 변경하여이 줄을 생략 할 수 있습니다 function (total, pair)function (total, [key, value])
야쿱 Zawiślak

entries이 작업을 수행하는 더 확실한 방법 이지만 keys성능이 떨어집니다. hackernoon.com/…
robdonn

@faboulaws Object.entries (o); // [[ "a", {value : 1}], [ "b", {value : 2}], [ "c", {value : 3}]]
Thomas

19

우선, 이전 값이 줄어드는 것을 얻지 못합니다 .

의사 코드에는가 return previous.value + current.value있으므로 previous객체가 아닌 다음 호출시 값이됩니다.

둘째, reduce객체가 아닌 Array 메서드이며 객체의 속성을 반복 할 때 순서에 의존 할 수 없습니다 ( https://developer.mozilla.org/en-US/docs/ JavaScript / Reference / Statements / for ... in , 이것은 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;
});

팻 화살표 함수 구문 (Firefox Nightly에서 이미 사용됨)을 사용하는 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

삼:

[{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
Johan


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 ​​() 를 사용하여 객체를 배열로 만든 다음 배열로 줄일 수 있습니다. 그러나 중간 배열을 만들지 않고도 개체를 줄일 수 있습니다.

객체로 작업하기위한 작은 도우미 라이브러리 odict 를 만들었습니다 .

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

Object 프로토 타입에 추가 할 수도 있습니다.

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

실제로 답변에서 확인되지 않았으므로 Underscore 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

유용하지 않습니다 "이 다른 라이브러리를보십시오"
Grunion Shaftoe

유용하지 않음
Chris Dolphin

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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.