[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
와 관련된 수학 을 추가하려고합니다 .undefined
NaN
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
것이 그래서 undefined
및 undefined + 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
은 ASaccumulator
와 같은 배열의 첫 번째 항목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}; })