知っておくべき 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 デプロイメントの実装

推薦する

ブラウザのCSS、JavaScript、背景画像のキャッシュをクリアする簡単な方法

実際のプロジェクト開発プロセスでは、ページがサーバーにアップロードされます。サーバーへの負荷を軽減し...

非常に便利な CSS 開発ツール 8 つを紹介

CSS3 パターン ギャラリーこの CSS3 パターン ライブラリには、純粋な CSS3 を使用して...

vue+el-upload は複数ファイルの動的アップロードを実現します

vue+el-upload 複数ファイルの動的アップロード、参考までに具体的な内容は以下のとおりです...

CSS3 で作成された背景グラデーションアニメーション効果

成果を達成する 実装コードhtml <h1 class="text-light&qu...

Win7 での mysql5.5 インストール グラフィック チュートリアル

MySQL のインストールは比較的簡単なので、通常は次のステップに直接進み、注意が必要な点に集中する...

JavaScriptで配列かどうかを判断するためのさまざまな方法のまとめ

目次序文配列.isArrayコンストラクタインスタンスプロトタイプオブジェクト.プロトタイプ.toS...

CSS3は背景画像にマスクを設定し、マスクスタイルの継承の問題を解決します。

多くの場合、透明度の設定やぼかしなど、写真の背景を加工する必要があります。 ただし、背景画像が配置さ...

Tomcat で server.xml と content.xml を変更した後の自動復元の問題の解決方法

設定ファイルを server.xml と content.xml に書き込みます。サーバーを再起動す...

MySQLデータベースのマスタースレーブ同期の実際のプロセスの詳細な説明

目次インストール環境の説明MySQLデータベースサービスをインストールするメインライブラリを構成する...

Linux の MySQL でリモート接続を承認する方法

注意: 他のマシン (IP) は、承認なしではクライアント経由で MySQL データベースに接続でき...

Vueでドラッグ可能なコンポーネントを実装する方法

この記事では、Vueでドラッグ可能なコンポーネントとドラッグ可能なコンポーネントを実装する方法を参考...

MySQL トランザクション分離レベルの原則例分析

導入あなたも面接でこれに遭遇したことがあるはずです。トランザクションの分離レベルについてお話ししまし...

Nginx は gzip 圧縮に基づいてアクセス速度を向上します

1. nginx はなぜ gzip を使用するのですか? 1. 圧縮の役割:ページがgzipで圧縮さ...

JavaScript 関数型プログラミングの基礎

目次1. はじめに2. 関数型プログラミングとは何ですか? 3. 純粋関数(関数型プログラミングの基...

CSSでできるならJavaScriptは使わない

序文JavaScript で記述できるアプリケーションは、最終的には JavaScript で記述さ...