知っておくべき JS 配列削減の高度な使い方 25 選

知っておくべき JS 配列削減の高度な使い方 25 選

序文

Reduce は ES5 で追加された新しい従来の配列メソッドの 1 つです。forEach、filter、map と比較すると、実際の使用ではやや軽視されているようです。私の周りの人々もあまり使用していないことがわかり、このような強力なメソッドが徐々に埋もれていくことにつながっています。

頻繁にreduceを使用するのであれば、このような便利なものを見逃すわけにはいきません。まだ埃の中から取り出して、きれいに拭いて、その高度な使い方をみんなに紹介しなければなりません。このような有用な方法は、世間に埋もれるべきではない。

以下は、reduce の構文の簡単な説明です。詳細については、MDN の Reduce() の関連する説明を参照してください。

  • 定義: 配列内の各要素に対してカスタムアキュムレータを実行し、結果を単一の戻り値に集約します。
  • フォーマット: array.reduce((t, v, i, a) => {}, initValue)
  • パラメータ
    • callback: コールバック関数(必須)
    • initValue: 初期値(オプション)
  • コールバック関数のパラメータ
    • total(t): 計算が完了した後のアキュムレータの戻り値(必須)
    • value(v): 現在の要素(必須)
    • index(i): 現在の要素のインデックス(オプション)
    • array(a): 現在の要素が属する配列オブジェクト(オプション)
  • プロセス
    • 累積結果の初期値として t を使用します。t が設定されていない場合は、配列の最初の要素が初期値として使用されます。
    • トラバーサルを開始し、アキュムレータを使用してvを処理し、vからtへのマッピング結果を蓄積し、ループを終了してtを返します。
    • 次のループに入り、配列の最後の要素まで上記の操作を繰り返します。
    • トラバーサルを終了し、最後のtを返す

Reduce の本質は、配列メンバーに 1 つずつ累積器を適用し、前の出力の値を次の入力の値として使用することです。簡単な例を使って、reduce の計算結果を見てみましょう。

定数arr = [3, 5, 1, 4, 2];
定数 a = arr.reduce((t, v) => t + v);
// 次と同等 const b = arr.reduce((t, v) => t + v, 0);

コードがよくわからなくても大丈夫です。reduce 関数の GIF を投稿すれば理解できるはずです。

Reduce は、基本的に、ユーザー定義のアキュムレータを介して配列メンバーに対してカスタム累積を実行し、アキュムレータによって生成された値を取得するアキュムレータ関数です。さらに、reduce には弟分の ReduceRight があります。2 つのメソッドの機能は実際には同じですが、reduce は昇順で実行され、reduceRight は降順で実行される点が異なります。

空の配列に対してreduce()とreduceRight()を呼び出してもコールバック関数は実行されないため、reduce()は空の配列に対して無効とみなされます。

高度な使用法

上記の簡単な例だけでは、reduce が何であるかを説明するには不十分です。 Reduce の威力を示すために、Reduce の高度な使用法を適用するための 25 のシナリオを紹介します。いくつかの高度な使用法は、他の方法と組み合わせて実現する必要がある場合があり、これにより、reduce の多様化の可能性が広がります。

一部のサンプルコードの書き方は少々雑なところがあるかもしれません。慣れていない方は自分の癖に合わせて書き直してください。

蓄積して増やす

関数 Accumulation(...vals) {
    vals.reduce((t, v) => t + v, 0) を返します。
}

関数乗算(...vals) {
    vals.reduce((t, v) => t * v, 1); を返します。
}
累積(1, 2, 3, 4, 5); // 15
乗算(1, 2, 3, 4, 5); // 120

加重合計

定数スコア = [
    { スコア: 90、件名: "中国語"、重み: 0.5 }、
    { スコア: 95、科目: "数学"、重み: 0.3 }、
    { スコア: 85、件名: "英語"、重み: 0.2 }
];
const result = scores.reduce((t, v) => t + v.score * v.weight, 0); // 90.5

逆に

関数Reverse(arr = []) {
    arr.reduceRight((t, v) => (t.push(v), t), []); を返します。
}
逆順([1, 2, 3, 4, 5]); // [5, 4, 3, 2, 1]

マップとフィルターを置き換える

定数arr = [0, 1, 2, 3];

// マップを置き換える: [0, 2, 4, 6]
定数a = arr.map(v => v * 2);
定数 b = arr.reduce((t, v) => [...t, v * 2], []);

// フィルターを置換: [2, 3]
定数 c = arr.filter(v => v > 1);
定数 d = arr.reduce((t, v) => v > 1 ? [...t, v] : t, []);

// マップとフィルターを置き換えます: [4, 6]
定数 e = arr.map(v => v * 2).filter(v => v > 2);
定数 f = arr.reduce((t, v) => v * 2 > 2 ? [...t, v * 2] : t, []);

一部と全部を置き換える

定数スコア = [
    { スコア: 45、件名: "中国語" },
    { スコア: 90、科目: "数学" },
    { スコア: 60、件名: "英語" }
];

// いくつかを置き換えます: 少なくとも 1 つの修飾子 const isAtLeastOneQualified = scores.reduce((t, v) => t || v.score >= 60, false); // true

// すべて置換: すべて修飾子付き const isAllQualified = scores.reduce((t, v) => t && v.score >= 60, true); // false

配列の分割

関数Chunk(arr = [], サイズ = 1) {
    arr.length を返します。arr.reduce((t, v) => (t[t.length - 1].length === size ? t.push([v]) : t[t.length - 1].push(v), t), [[]]) : [];
}
定数arr = [1, 2, 3, 4, 5];
チャンク(arr, 2); // [[1, 2], [3, 4], [5]]

配列フィルタリング

関数 Difference(arr = [], oarr = []) {
    arr.reduce((t, v) => (!oarr.includes(v) && t.push(v), t), []); を返します。
}
定数arr1 = [1, 2, 3, 4, 5];
定数arr2 = [2, 3, 6]
差(arr1, arr2); // [1, 4, 5]

配列の充填

関数Fill(arr = [], val = "", start = 0, end = arr.length) {
    start < 0 || start >= end || end > arr.length の場合、arr を返します。
    戻る [
        ...arr.slice(0, 開始),
        ...arr.slice(start, end).reduce((t, v) => (t.push(val || v), t), []),
        ...arr.slice(終了、arr.length)
    ];
}
定数arr = [0, 1, 2, 3, 4, 5, 6];
Fill(arr, "aaa", 2, 5); // [0, 1, "aaa", "aaa", "aaa", 5, 6]

配列の平坦化

関数 Flat(arr = []) {
    arr.reduce((t, v) => t.concat(Array.isArray(v) ? Flat(v) : v), []) を返します。
}
定数arr = [0, 1, [2, 3], [4, 5, [6, 7]], [8, [9, 10, [11, 12]]]];
Flat(arr); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

アレイ重複排除

関数Uniq(arr = []) {
    arr.reduce((t, v) => t.includes(v) ? t : [...t, v], []); を返します。
}
定数arr = [2, 1, 0, 3, 2, 1, 2];
ユニーク(arr); // [2, 1, 0, 3]

配列の最大値と最小値

関数Max(arr = []) {
    arr.reduce((t, v) => t > v ? t : v); を返します。
}

関数 Min(arr = []) {
    arr.reduce((t, v) => t < v ? t : v); を返します。
}
定数arr = [12, 45, 21, 65, 38, 76, 108, 43];
最大(arr); // 108
最小(arr); // 12

配列メンバーは独立して分解される

関数Unzip(arr = []) {
    arr.reduce() を返す
        (t, v) => (v.forEach((w, i) => t[i].push(w)), t),
        Array.from({ length: Math.max(...arr.map(v => v.length)) }).map(v => [])
    );
}
定数 arr = [["a", 1, true], ["b", 2, false]];
Unzip(arr); // [["a", "b"], [1, 2], [true, false]]

配列メンバー数

関数Count(arr = []) {
    arr.reduce((t, v) => (t[v] = (t[v] || 0) + 1, t), {}); を返します。
}
定数arr = [0, 1, 1, 2, 2, 2];
Count(arr); // { 0: 1, 1: 2, 2: 3 }

この方法は、文字統計と単語統計の原理に基づいています。パラメータを入力すると、文字列を配列に処理するだけです。

配列メンバー位置レコード

関数 Position(arr = [], val) {
    arr.reduce((t, v, i) => (v === val && t.push(i), t), []); を返します。
}
定数arr = [2, 1, 5, 4, 2, 1, 6, 6, 7];
位置(arr, 2); // [0, 4]

配列メンバー属性のグループ化

関数グループ(arr = [], キー) {
    キーを返します? arr.reduce((t, v) => (!t[v[key]] && (t[v[key]] = []), t[v[key]].push(v), t), {}) : {};
}
定数arr = [
    { 地域: "GZ", 名前: "YZW", 年齢: 27 },
    { 地域: "GZ", 名前: "TYJ", 年齢: 25 },
    { エリア: "SZ", 名前: "AAA", 年齢: 23 },
    { エリア: "FS", 名前: "BBB", 年齢: 21 },
    { エリア: "SZ", 名前: "CCC", 年齢: 19 }
]; // グループ化の基準として面積を使用する Group(arr, "area"); // { GZ: Array(2), SZ: Array(2), FS: Array(1) }

配列メンバーのキーワード統計

関数キーワード(arr = [], keys = []) {
    戻り値 keys.reduce((t, v) => (arr.some(w => w.includes(v)) && t.push(v), t), []);
}
定数テキスト = [
    「今日はいい天気だから釣りに行きたい」
    「宿題をしながらテレビを見ます」
    「シャオミンは、隣に座っているシャオホンと、隣に座っているシャオジュンが好きです。彼はとても気まぐれです」
    「最近、仕事をサボりたがる人が多すぎる。ちゃんとコードを書かずに空想にふけっている。」
];
const keyword = ["lazy", "like", "sleep", "fishing", "great", "while", "tomorrow"];
Keyword(text, keyword); // ["like", "slacking off", "really nice", "while"]

文字列の反転

関数ReverseStr(str = "") {
    str.split("").reduceRight((t, v) => t + v); を返します。
}
const str = "reduce が最善です";
ReverseStr(str); // "最も強力なエクーダー"

デジタルミレニアル世代

関数 ThousandNum(num = 0) {
    const str = (+num).toString().split(".");
    const int = nums => nums.split("").reverse().reduceRight((t, v, i) => t + (i % 3 ? v : `${v},`), "").replace(/^,|,$/g, "");
    const dec = nums => nums.split("").reduce((t, v, i) => t + ((i + 1) % 3 ? v : `${v},`), "").replace(/^,|,$/g, "");
    str.length > 1 を返します? `${int(str[0])}.${dec(str[1])}` : int(str[0]);
}
ThousandNum(1234); // "1,234"
ThousandNum(1234.00); // "1,234"
ThousandNum(0.1234); // "0.123,4"
ThousandNum(1234.5678); // "1,234.567,8"

非同期蓄積

非同期関数 AsyncTotal(arr = []) {
    戻り値 arr.reduce(async(t, v) => {
        定数 at = t を待機します。
        todo を待機します。
        at[v] = する;
        戻る;
    }, Promise.resolve({}));
}
const result = await AsyncTotal(); // 非同期サラウンドで使用する必要があります

フィボナッチ数列

関数フィボナッチ(len = 2) {
    const arr = [...新しい配列(len).keys()];
    arr.reduce((t, v, i) => (i > 1 && t.push(t[i - 1] + t[i - 2]), t), [0, 1]); を返します。
}
フィボナッチ(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

URLパラメータのデシリアライズ

関数 ParseUrlSearch() {
    location.search.replace(/(^\?)|(&$)/g, "").split("&").reduce((t, v) => { を返します。
        const [キー、値] = v.split("=");
        t[キー] = decodeURIComponent(val);
        t を返します。
    }, {});
}
// URL が https://www.baidu.com?age=25&name=TYJ であると仮定します。
ParseUrlSearch(); // { 年齢: "25", 名前: "TYJ" }

URLパラメータのシリアル化

関数 StringifyUrlSearch(検索 = {}) {
    Object.entries(search).reduce() を返します。
        (t, v) => `${t}${v[0]}=${encodeURIComponent(v[1])}&`、
        Object.keys(search).length ? "?" : ""
    ).replace(/&$/, "");
}
StringifyUrlSearch({ age: 27, name: "YZW" }); // "?age=27&name=YZW"

オブジェクト内の指定されたキーの値を返します

関数 GetKeys(obj = {}, keys = []) {
    Object.keys(obj).reduce((t, v) => (keys.includes(v) && (t[v] = obj[v]), t), {}); を返します。
}
定数ターゲット = { a: 1、 b: 2、 c: 3、 d: 4 };
const キーワード = ["a", "d"];
GetKeys(ターゲット、キーワード); // { a: 1, d: 4 }

配列からオブジェクトへ

定数人 = [
    { 地域: "GZ", 名前: "YZW", 年齢: 27 },
    { エリア: "SZ", 名前: "TYJ", 年齢: 25 }
];
const map = people.reduce((t, v) => {
    const { 名前、... 残り } = v;
    t[名前] = 残り;
    t を返します。
}, {}); // { YZW: {…}, TYJ: {…} }

Redux Compose関数の原則

関数Compose(...関数) {
    (関数の長さが0の場合){
        引数 => 引数を返します。
    }
    関数の長さが1の場合
        funs[0]を返します。
    }
    funs.reduce((t, v) => (...arg) => t(v(...arg))); を返します。
}

互換性とパフォーマンス

使いやすいですが、互換性はどうでしょうか? Caniuse で検索すると、互換性が非常に高く、どのプロジェクトでも大胆に使用できます。想像力を惜しまず、文章作成スキルをフルに発揮してください。頻繁に何らかの累積を実行する関数の場合、reduce が間違いなく推奨される方法です。

さらに、reduce のパフォーマンスはどうなのかと尋ねる学生もいるかもしれません。次に、for、forEach、map、reduce の 4 つのメソッドに対して 1 から 100,000 までの累積演算を同時に実行し、4 つのメソッドそれぞれの実行時間を確認します。

// 長さ 100000 の配列を作成します。const list = [...new Array(100000).keys()];

// のために
console.time("に対して");
結果1 = 0 とします。
(i = 0 とします; i < list.length; i++) {
    結果1 += i + 1;
}
コンソールログ(結果1);
console.timeEnd("for");

// 各
コンソールで時間を設定します。
結果2 = 0 とします。
リスト.forEach(v => (result2 += v + 1));
コンソールログ(結果2);
コンソールのtimeEnd("forEach");

// マップ
console.time("マップ");
結果3 = 0 とします。
list.map(v => (result3 += v + 1, v));
コンソールログ(結果3);
console.timeEnd("マップ");

// 減らす
console.time("短縮");
const result4 = list.reduce((t, v) => t + v + 1, 0);
コンソールログ(結果4);
console.timeEnd("減らす");
累積操作実行時間
のために6.719970703125ms
3.696044921875ms
地図3.554931640625ms
減らす2.806884765625ms

上記のコードは、16G メモリと 512G フラッシュ メモリを搭載した MacBook Pro 2019 15 インチの Chrome 79 で実行されています。マシンや環境によって、上記のコードの実行結果が異なる場合があります。

複数のマシンと複数のブラウザを同時にテストし、10 回以上連続して操作を実行しました。reduce の全体的な平均実行時間は、他の 3 つの方法よりもわずかに速いことがわかりましたので、安心して使用できます。この記事では主にreduceの使用テクニックについて説明しています。reduceの互換性やパフォーマンスについて疑問がある場合は、関連資料を参照して検証することができます。

最後に、reduce によって生成された掛け算の表を示します。1 を 7 倍すると 7、2 を 7 倍すると 48、3 月 8 日は国際女性デー、5 月 1 日は労働者の日、6 月 1 日は子供の日です。

要約する

これで、知っておくべき JS 配列の削減の高度な使用法 25 個に関するこの記事は終了です。JS 配列の削減の高度な使用法に関する詳細なコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • JavaScript の配列の Reduce メソッドの詳細な説明
  • JS配列Reduce()メソッドと高度なテクニックの詳細な説明
  • js配列メソッドは、従来の使用法のコード共有を削減します
  • JS配列reduce()メソッドの原理と使い方の分析
  • Javascript 配列メソッドの魔法をシェアする
  • JS配列Reduceメソッドの機能と使い方の詳しい説明
  • JavaScript配列メソッドの解析reduce
  • JS配列メソッドreduceの使用例の分析
  • js配列のfind、some、filter、reduceの違いの詳細な説明
  • JavaScript 配列の共通インスタンスメソッドを削減

<<:  MySQLのユーザーアカウント管理と権限管理の詳細な説明

>>:  Tomcat および Web アプリケーションの Docker デプロイメントの実装

推薦する

美しいチェックボックススタイル(複数選択ボックス)はIE8/9/10、FFなどと完全に互換性があります。

恥ずかしながら、このようなよく使われるチェックボックスのスタイルを変更するために、Baidu で長い...

IE アドレスバーのアイコン表示問題を解決する 3 つの手順

<br />この Web ページ制作スキル チュートリアルは、Web サイトのアイコンを...

Docker x509 の安全でないレジストリ問題を解決する

Docker をインストールした後、会社が構築したプライベート サーバー Harbor からプルしよ...

Vue2.x における双方向バインディングの原理と実装

目次1. 実施プロセス2. オブザーバーを表示する3. ウォッチャーを実装する4. コンパイルを実装...

Windows 10 で MySQL をダウンロードするための詳細なチュートリアル

MySQL のバージョンは、Enterprise Edition と Community Editi...

CSS3 フレックスレイアウトを使用して要素を均等に分散するサンプルコード

この記事では主に、CSS3 フレックスレイアウトを使用して要素を均等に配置する方法を紹介します。自分...

高性能な HTML アプリケーションを作成するためのヒント

Web ページのパフォーマンスを向上させるにはどうすればよいでしょうか?ほとんどの開発者は、Java...

Vuex環境の詳細な説明

目次Vuex環境を構築する要約するVuex環境を構築するsrcディレクトリにフォルダstoreを作成...

formData 形式タイプを使用してファイルをアップロードする Vue の例

Vue では、一般的にフロントエンドとバックエンドを分離したプロジェクトがあり、データ操作を実装する...

CSS3 での 2D および 3D 変換の実装

CSS3 は、要素の 2D 平面変換と視覚的な 3D 空間変換を実装します。2D 変換はより頻繁に使...

Linux で推奨される 9 つの優れたコード比較ツールの概要

コードを書くとき、2 つのファイル間の違い、または同じファイルの異なるバージョン間の違いを知る必要が...

MySql 範囲内の検索時にインデックスが有効にならない理由の分析

1 問題の説明この記事では、確立された複合インデックスをソートし、レコード内の非インデックス フィー...

MySQL における悲観的ロックと楽観的ロック

リレーショナル データベースでは、悲観的ロックと楽観的ロックがリソース同時実行シナリオのソリューショ...

jQueryはすべてのショッピングカート機能を実装します

目次1. すべて選択2. 商品の数量を増やすか減らす3. 商品の小計を変更する4. 合計と合計額を計...

MySQLでデータをエクスポートするいくつかの方法の詳細な説明

MySQL データをエクスポートする目的は、データベースのバックアップ、テーブル構造のエクスポート、...