Javascriptの配列方法reduceの優れた使い方
7752 ワード
Javascript配列方法では、
構文
配列arr=[1,2,3,4]を実現するための配列の和は、配列をオブジェクト に変換する.は、より大きな配列 を展開する.は、巡回中に2回の計算を行う .は、マッピングとフィルタ関数を組み合わせる .は、非同期関数 を順次実行する.
配列をオブジェクトに変換
実際の業務開発においては、バックグラウンドインターフェースが戻る配列タイプに遭遇したことがありますが、それをキーとしてid値に基づいて変換し、各配列をvalueのオブジェクトとして検索する必要があります.
たとえば:
このような場面を考えてみてください.私たちはテキスト列を読み込みます.カンマで行を区切って、より大きな配列リストを作成したいです.
もう一つのよくある増加配列の場合はflatMapであり、場合によってはmap方法で二次配列を展開する必要があります.このときreduceで扁平化ができます.
たとえば:
配列を二回計算する必要がある場合があります.例えば、デジタルリストの最大値と最小値を計算したいかもしれません.私たちは二回にわたってこのようにすることができます.
それとも前のユーザーリストですか?メールアドレスがない人のユーザ名を見つけて、カンマで区切られた文字列を返したいです.一つの方法は二つの別々の動作を使用することである.電子メールなしフィルタリングされたエントリを取得する .ユーザ名を取得して、連接します. それらを一緒に置くと、このように見えるかもしれません.
非同期関数を順番に実行します.
私たちができるもう一つのことは.reduce(並行ではなく)順にpromisesを実行します.API要求に対して速度制限がある場合、または各prmiseの結果を次のpromiseに伝える必要がある場合、
一例を挙げると、
ここでPromiseは初期値
以下は
map
、filter
、forEach
などの一般的な反復方法に比べて、reduce
はしばしば無視されています.今日は私たちが実際に開発したreduce
の中で、どのような効果があるかを探ってみます.次に、reduce
文法から紹介します.構文
array.reduce(function(accumulator, arrayElement, currentIndex, arr), initialValue)
初期値が入ると、accumullatorの最初の反復は初期値であり、そうでなければ配列の最初の要素である.後続の反復は、前回の反復関数から返された結果である.したがって、配列の長さがnであれば、着信初期値の場合、反復回数はnである.そうでないとn-1です配列arr=[1,2,3,4]を実現するための配列の和
let arr = [1,2,3,4];
arr.reduce(function(pre,cur){return pre + cur}); // return 10
実際にreduceには多くの重要な使用法があります.これはアキュムレータの値が単純なタイプ(たとえば数字や文字列)でなくてもいいからです.配列やオブジェクトなどの構造的なタイプでもいいです.これによって、他の有用なことができます.配列をオブジェクトに変換
実際の業務開発においては、バックグラウンドインターフェースが戻る配列タイプに遭遇したことがありますが、それをキーとしてid値に基づいて変換し、各配列をvalueのオブジェクトとして検索する必要があります.
たとえば:
const userList = [
{
id: 1,
username: 'john',
sex: 1,
email: '[email protected]'
},
{
id: 2,
username: 'jerry',
sex: 1,
email: '[email protected]'
},
{
id: 3,
username: 'nancy',
sex: 0,
email: ''
}
];
このライブラリを使ったことがあれば、_.keyBy
という方法で変換できますが、reduce
を使ってもこのような需要が実現できます.function keyByUsernameReducer(acc, person) {
return {...acc, [person.id]: person};
}
const userObj = peopleArr.reduce(keyByUsernameReducer, {});
console.log(userObj);
小数を大行列に展このような場面を考えてみてください.私たちはテキスト列を読み込みます.カンマで行を区切って、より大きな配列リストを作成したいです.
const fileLines = [
'Inspector Algar,Inspector Bardle,Mr. Barker,Inspector Barton',
'Inspector Baynes,Inspector Bradstreet,Inspector Sam Brown',
'Monsieur Dubugue,Birdy Edwards,Inspector Forbes,Inspector Forrester',
'Inspector Gregory,Inspector Tobias Gregson,Inspector Hill',
'Inspector Stanley Hopkins,Inspector Athelney Jones'
];
function splitLineReducer(acc, line) {
return acc.concat(line.split(/,/g));
}
const investigators = fileLines.reduce(splitLineReducer, []);
console.log(investigators);
// [
// "Inspector Algar",
// "Inspector Bardle",
// "Mr. Barker",
// "Inspector Barton",
// "Inspector Baynes",
// "Inspector Bradstreet",
// "Inspector Sam Brown",
// "Monsieur Dubugue",
// "Birdy Edwards",
// "Inspector Forbes",
// "Inspector Forrester",
// "Inspector Gregory",
// "Inspector Tobias Gregson",
// "Inspector Hill",
// "Inspector Stanley Hopkins",
// "Inspector Athelney Jones"
// ]
長さ5の配列から始めて、最後に16の長さの配列が得られます.もう一つのよくある増加配列の場合はflatMapであり、場合によってはmap方法で二次配列を展開する必要があります.このときreduceで扁平化ができます.
たとえば:
Array.prototype.flatMap = function(f) {
const reducer = (acc, item) => acc.concat(f(item));
return this.reduce(reducer, []);
}
const arr = [" ", "", " "]
const arr1 = arr.map(s => s.split(""))
// [[" ", " ", " ", " ", " ", " "],[""],[" ", " ", " "]]
const arr2 = arr.flatMap(s => s.split(''));
// [" ", " ", " ", " ", " ", " ", "", " ", " ", " "]
一回の巡回中に二回の計算を行います.配列を二回計算する必要がある場合があります.例えば、デジタルリストの最大値と最小値を計算したいかもしれません.私たちは二回にわたってこのようにすることができます.
const readings = [0.3, 1.2, 3.4, 0.2, 3.2, 5.5, 0.4];
const maxReading = readings.reduce((x, y) => Math.max(x, y), Number.MIN_VALUE);
const minReading = readings.reduce((x, y) => Math.min(x, y), Number.MAX_VALUE);
console.log({minReading, maxReading});
// {minReading: 0.2, maxReading: 5.5}
これは私たちの配列を2回遍歴する必要があります.しかし、時々私達はこのようにしたくないかもしれません.reduce()は私たちの欲しいタイプに戻ります.私たちは数字を返す必要がありません.二つの値を一つのオブジェクトに符号化できます.その後、私たちは反復のたびに2回計算し、配列だけを巡回します.const readings = [0.3, 1.2, 3.4, 0.2, 3.2, 5.5, 0.4];
function minMaxReducer(acc, reading) {
return {
minReading: Math.min(acc.minReading, reading),
maxReading: Math.max(acc.maxReading, reading),
};
}
const initMinMax = {
minReading: Number.MAX_VALUE,
maxReading: Number.MIN_VALUE,
};
const minMax = readings.reduce(minMaxReducer, initMinMax);
console.log(minMax);
// {minReading: 0.2, maxReading: 5.5}
マッピングとフィルタを一つのプロセスに統合します.それとも前のユーザーリストですか?メールアドレスがない人のユーザ名を見つけて、カンマで区切られた文字列を返したいです.一つの方法は二つの別々の動作を使用することである.
function notEmptyEmail(x) {
return !!x.email
}
function notEmptyEmailUsername(a, b) {
return a ? `${a},${b.username}` : b.username
}
const userWithEmail = userList.filter(notEmptyEmail);
const userWithEmailFormatStr = userWithEmail.reduce(notEmptyEmailUsername, '');
console.log(userWithEmailFormatStr);
// 'john,jerry'
現在、このコードは完全に読み取り可能で、小さいサンプルデータには性能に問題はないですが、もし我々が巨大な配列を持っていたら?もし私たちがreducerのフィードバックを修正したら、私たちは一回ですべてのことを完成できます.function notEmptyEmail(x) {
return !!x.email
}
function notEmptyEmailUsername(usernameAcc, person){
return (notEmptyEmail(person))
? (usernameAcc ? `${usernameAcc},${person.username}` : `${person.username}`) : usernameAcc;
}
const userWithEmailFormatStr = userList.reduce(notEmptyEmailUsername, '');
console.log(userWithEmailFormatStr);
// 'john,jerry'
このバージョンでは、私たちは一度の配列だけを巡回して、一般的にはfilter
とmap
の組み合わせを使用することを推奨しています.性能問題が発見されない限り、reduce
を使用して最適化を行うことを推奨しています.非同期関数を順番に実行します.
私たちができるもう一つのことは.reduce(並行ではなく)順にpromisesを実行します.API要求に対して速度制限がある場合、または各prmiseの結果を次のpromiseに伝える必要がある場合、
reduce
はあなたを助けることができます.一例を挙げると、
userList
配列の各々にメッセージを取得したいと仮定する.function fetchMessages(username) {
return fetch(`https://example.com/api/messages/${username}`)
.then(response => response.json());
}
function getUsername(person) {
return person.username;
}
async function chainedFetchMessages(p, username) {
// In this function, p is a promise. We wait for it to finish,
// then run fetchMessages().
const obj = await p;
const data = await fetchMessages(username);
return { ...obj, [username]: data};
}
const msgObj = userList
.map(getUsername)
.reduce(chainedFetchMessages, Promise.resolve({}))
.then(console.log);
// {glestrade: [ … ], mholmes: [ … ], iadler: [ … ]}
async
関数はPromiseオブジェクトに戻り、then
方法を用いてコールバック関数を追加することができる.関数が実行されると、一旦await
に遭遇すると、非同期動作が完了するまで、関数の後の文が実行される.ここでPromiseは初期値
Promise.resolve()
として伝えられます.最初のAPI呼び出しはすぐに実行されます.以下は
async
シンタックス飴を使わないバージョンです.function fetchMessages(username) {
return fetch(`https://example.com/api/messages/${username}`)
.then(response => response.json());
}
function getUsername(person) {
return person.username;
}
function chainedFetchMessages(p, username) {
// In this function, p is a promise. We wait for it to finish,
// then run fetchMessages().
return p.then((obj)=>{
return fetchMessages(username).then(data=>{
return {
...obj,
[username]: data
}
})
})
}
const msgObj = peopleArr
.map(getUsername)
.reduce(chainedFetchMessages, Promise.resolve({}))
.then(console.log);
// {glestrade: [ … ], mholmes: [ … ], iadler: [ … ]}
PS:先端情報、技術乾燥品は、公衆番号「先端新視界」に注目してください.