[javascript] 자바 스크립트로 객체 배열 축소

a.x각 요소에 대해 합계 를 원한다고 가정 해보십시오 arr.

arr = [{x:1},{x:2},{x:4}]
arr.reduce(function(a,b){return a.x + b.x})
>> NaN

나는 어느 시점에서 도끼가 정의되어 있지 않다고 생각합니다.

다음은 잘 작동합니다

arr = [1,2,4]
arr.reduce(function(a,b){return a + b})
>> 7

첫 번째 예에서 내가 뭘 잘못하고 있니?



답변

첫 번째 반복 후 숫자를 반환 한 다음 그 속성을 가져 와서 x다음 객체에 추가하고 결과 undefined와 관련된 수학 을 추가하려고합니다 .undefinedNaN

x매개 변수의 x 속성 합계를 가진 속성을 포함하는 객체를 반환 하십시오.

var arr = [{x:1},{x:2},{x:4}];

arr.reduce(function (a, b) {
  return {x: a.x + b.x}; // returns object with property x
})

// ES6
arr.reduce((a, b) => ({x: a.x + b.x}));

// -> {x: 7}

주석에서 추가 된 설명 :

다음 반복에서 변수로 [].reduce사용 된 각 반복의 리턴 값입니다 a.

반복 1 : a = {x:1}, b = {x:2}, {x: 3}에 할당 a반복 2

반복 2 : a = {x:3}, b = {x:4}.

예제의 문제는 숫자 리터럴을 반환한다는 것입니다.

function (a, b) {
  return a.x + b.x; // returns number literal
}

반복 1 : a = {x:1}, b = {x:2}, // returns 3등의 a다음 반복에서

반복 2 : a = 3, b = {x:2}리턴NaN

숫자 리터럴은 3(일반적으로)라는 속성이없는 x것이 그래서 undefinedundefined + b.x반환 NaN하고 NaN + <anything>항상NaN

설명 : 나는 숫자 스레드를 얻는 마법의 숫자로 줄이려면 선택적 매개 변수를 전달하는 것이 더 깨끗하다는 생각에 동의하지 않기 때문에이 스레드의 다른 최상위 답변보다 내 방법을 선호합니다. 줄이 적을 수 있지만 읽을 수는 없습니다.


답변

이를 달성하는 더 확실한 방법은 초기 값을 제공하는 것입니다.

var arr = [{x:1}, {x:2}, {x:4}];
arr.reduce(function (acc, obj) { return acc + obj.x; }, 0); // 7
console.log(arr);

익명 함수가 처음 호출되면로 호출되어 (0, {x: 1})를 반환합니다 0 + 1 = 1. 다음 번에는로 호출되어 (1, {x: 2})를 반환합니다 1 + 2 = 3. 그런 다음으로 호출되어 (3, {x: 4})마침내을 반환 7합니다.


답변

TL; DR, 초기 값 설정

파괴 사용

arr.reduce( ( sum, { x } ) => sum + x , 0)

파괴하지 않고

arr.reduce( ( sum , cur ) => sum + cur.x , 0)

Typescript로

arr.reduce( ( sum, { x } : { x: number } ) => sum + x , 0)

파괴 방법을 사용해 봅시다 :

const arr = [ { x: 1 }, { x: 2 }, { x: 4 } ]
const result = arr.reduce( ( sum, { x } ) => sum + x , 0)
console.log( result ) // 7

이것의 핵심은 초기 값을 설정하는 것입니다. 리턴 값은 다음 반복의 첫 번째 매개 변수가됩니다.

최고 답변에 사용 된 기술은 관용적이지 않습니다

수락 된 답변은 “선택적”값을 전달하지 말 것을 제안합니다. 관용적 인 방법은 두 번째 매개 변수가 항상 포함되어 있기 때문에 이것은 잘못 입니다. 왜? 세 가지 이유 :

1. 위험
-콜백 기능이 부주의 한 경우 초기 값을 전달하지 않으면 위험하며 부작용과 돌연변이가 발생할 수 있습니다.

보다

const badCallback = (a,i) => Object.assign(a,i)

const foo = [ { a: 1 }, { b: 2 }, { c: 3 } ]
const bar = foo.reduce( badCallback )  // bad use of Object.assign
// Look, we've tampered with the original array
foo //  [ { a: 1, b: 2, c: 3 }, { b: 2 }, { c: 3 } ]

그러나 초기 값으로 이런 식으로 수행 한 경우 :

const bar = foo.reduce( badCallback, {})
// foo is still OK
foo // { a: 1, b: 2, c: 3 }

레코드의 경우, 원래 오브젝트를 변경하지 않으려면 첫 번째 매개 변수를 Object.assign빈 오브젝트로 설정하십시오 . 이와 같이 : Object.assign({}, a, b, c).

2-더 나은 유형 추론
-Typescript와 같은 도구 또는 VS Code와 같은 편집기를 사용하면 컴파일러에 초기를 알리는 이점이 있으며 잘못하면 오류가 발생할 수 있습니다. 초기 값을 설정하지 않으면 많은 상황에서 추측하지 못할 수 있으며 런타임 오류를 초래할 수 있습니다.

3-Functors 존중-JavaScript
는 내부 기능적 자식이 풀릴 때 가장 잘 나타납니다. 기능적 세계에는 “접는”방법이나 reduce배열 에 대한 표준이 있습니다 . 배열에 변형 을 접거나 적용 할 때 해당 배열의 값을 사용하여 새 유형을 구성합니다. 결과 유형을 전달해야합니다. 최종 유형이 배열, 다른 배열 또는 다른 유형의 값인 경우에도이를 수행해야합니다.

다른 방법으로 생각해 봅시다. JavaScript에서 함수는 데이터처럼 전달 될 수 있습니다. 이것이 콜백이 작동하는 방식입니다. 다음 코드의 결과는 무엇입니까?

[1,2,3].reduce(callback)

숫자를 반환합니까? 객체? 이것은 더 명확하게

[1,2,3].reduce(callback,0)

기능 프로그래밍 사양에 대한 자세한 내용은 https://github.com/fantasyland/fantasy-land#foldable을 참조 하십시오.

더 많은 배경

reduce방법에는 두 가지 매개 변수가 사용됩니다.

Array.prototype.reduce( callback, initialItem )

callback함수는 다음 매개 변수를 사용합니다

(accumulator, itemInArray, indexInArray, entireArray) => { /* do stuff */ }

첫 번째 반복의 경우

  • 경우에 initialItem제공되는 상기 reduce기능은 전달 initialItem은 AS accumulator와 같은 배열의 첫 번째 항목 itemInArray.

  • 경우 initialItem되어 있지 제공의 reduce함수로서 배열의 첫 번째 항목이 통과 initialItem하고 상기 어레이의 두 번째 항목 itemInArray동작을 혼동 할 수있다.

항상 Reduce의 초기 값을 설정하는 것을 가르치고 권장합니다.

다음에서 설명서를 확인할 수 있습니다.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

도움이 되었기를 바랍니다!


답변

다른 사람들 이이 질문에 대답했지만 다른 접근법으로 던질 것이라고 생각했습니다. 합산 도끼로 직접 이동하지 않고 (도에서 x로) 맵을 결합하고 (x를 추가하기 위해) 줄일 수 있습니다.

arr = [{x:1},{x:2},{x:4}]
arr.map(function(a) {return a.x;})
   .reduce(function(a,b) {return a + b;});

분명히 조금 느려질 것입니다.하지만 옵션으로 언급 할 가치가 있다고 생각했습니다.


답변

지적 된 것을 공식화하기 위해 감속기는 우연에 의해 동일한 유형일 수있는 두 개의 인수를 취하고 첫 번째 인수와 일치하는 유형을 리턴하는 이변 형입니다.

function reducer (accumulator: X, currentValue: Y): X { }

이것은 감속기의 몸체가 변환에 관한 것이어야 currentValue하고의 현재 값을 accumulator새로운 값으로 변환해야한다는 것을 의미합니다 accumulator.

누산기와 요소 값이 모두 같은 유형이지만 다른 목적으로 사용되기 때문에 이것은 추가 할 때 간단하게 작동합니다.

[1, 2, 3].reduce((x, y) => x + y);

그들은 모두 숫자이기 때문에 작동합니다.

[{ age: 5 }, { age: 2 }, { age: 8 }]
  .reduce((total, thing) => total + thing.age, 0);

이제 애그리 게이터에게 시작 가치를 부여합니다. 시작 값은 대부분의 경우 애그리 게이터가 될 것으로 예상되는 유형 (최종 값으로 나타날 것으로 예상되는 유형)이어야합니다. 이 작업을 수행하도록 강요받지 말아야하지만 그렇게해서는 안됩니다.하지만 명심해야합니다.

일단 알면 다른 n : 1 관계 문제에 대한 의미있는 축소를 작성할 수 있습니다.

반복되는 단어 제거하기 :

const skipIfAlreadyFound = (words, word) => words.includes(word)
    ? words
    : words.concat(word);

const deduplicatedWords = aBunchOfWords.reduce(skipIfAlreadyFound, []);

찾은 모든 단어의 수를 제공합니다 :

const incrementWordCount = (counts, word) => {
  counts[word] = (counts[word] || 0) + 1;
  return counts;
};
const wordCounts = words.reduce(incrementWordCount, { });

배열 배열을 단일 평면 배열로 줄이기 :

const concat = (a, b) => a.concat(b);

const numbers = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
].reduce(concat, []);

일의 배열에서 1 : 1과 일치하지 않는 단일 값으로 갈 때마다 감소가 고려됩니다.

실제로 맵과 필터는 모두 축소로 구현할 수 있습니다.

const map = (transform, array) =>
  array.reduce((list, el) => list.concat(transform(el)), []);

const filter = (predicate, array) => array.reduce(
  (list, el) => predicate(el) ? list.concat(el) : list,
  []
);

이것이 사용 방법에 대한 추가 컨텍스트를 제공하기를 바랍니다 reduce.

내가 아직 다루지 않은 이것에 대한 한 가지 추가 사항은 배열 요소가 함수이기 때문에 입력 및 출력 유형이 특히 동적이어야한다는 기대가있을 때입니다.

const compose = (...fns) => x =>
  fns.reduceRight((x, f) => f(x), x);

const hgfx = h(g(f(x)));
const hgf = compose(h, g, f);
const hgfy = hgf(y);
const hgfz = hgf(z);


답변

첫 번째 반복에서 ‘a’는 배열의 첫 번째 객체이므로 ax + bx는 1 + 2 즉 3을 반환합니다. 이제 다음 반복에서 반환 된 3은 a에 할당되므로 a는 n을 호출하는 숫자입니다. NaN을 줄 것이다.

간단한 해결책은 먼저 숫자를 배열로 매핑 한 다음 아래와 같이 줄입니다.

arr.map(a=>a.x).reduce(function(a,b){return a+b})

여기 arr.map(a=>a.x)에 숫자 배열 [1,2,4] .reduce(function(a,b){return a+b})을 제공 할 것입니다.

또 다른 간단한 해결책은 아래와 같이 0을 ‘a’에 할당하여 초기 합계를 0으로 제공하는 것입니다.

arr.reduce(function(a,b){return a + b.x},0)


답변

Reduce의 각 단계에서 새 {x:???}객체를 반환하지 않습니다 . 따라서 다음 중 하나를 수행해야합니다.

arr = [{x:1},{x:2},{x:4}]
arr.reduce(function(a,b){return a + b.x})

또는해야 할 일

arr = [{x:1},{x:2},{x:4}]
arr.reduce(function(a,b){return {x: a.x + b.x}; })