さまざまなプログラミング言語に配列の重複排除があることは誰もが知っていますが、この記事では、皆さんのお役に立つことを願って、JavaScript の配列重複排除について説明します。
二層ループ
おそらく最初に思いつくのは、indexOf を使用して判定をループすることですが、この方法の前に、まず最も独創的な方法を見てみましょう:
var array = [1, 1, '1', '1'];function unique(array) { // res用来存储结果 var res = []; for (var i = 0, arrayLen = array.length; i < arrayLen; i++) { for (var j = 0, resLen = res.length; j < resLen; j++ ) { if (array[i] === res[j]) { break; } } // 如果array[i]是唯一的,那么执行完循环,j等于resLen if (j === resLen) { res.push(array[i]) } } return res; }console.log(unique(array)); // [1, "1"]
この方法では、loop を使用します。ネスト、最も外側のループは array で、内側のループは res です。array[i] の値が res[j] の値と等しい場合、それらが等しくない場合は、ループから抜け出します。このとき、j の値は res と等しくなります。この特性に基づいて長さを判断し、その値を res に加算します。
なぜこの方法についてお話したいかというと、とても単純なようですが、それは————相性が良いからです。
indexOf
indexOf を使用して内部ループを簡素化できます:
var array = [1, 1, '1'];function unique(array) { var res = []; for (var i = 0, len = array.length; i < len; i++) { var current = array[i]; if (res.indexOf(current) === -1) { res.push(current) } } return res; }console.log(unique(array));
ソート後の重複排除
まず、sort メソッドを使用して重複排除された配列をソートし、同じ値がまとめて配置されることを想像してください。現在の要素が前の要素と同じであるかどうかを判断することができます。同じである場合は、それを res に追加します:
var array = [1, 1, '1'];function unique(array) { var res = []; var sortedArray = array.concat().sort(); var seen; for (var i = 0, len = sortedArray.length; i < len; i++) { // 如果是第一个元素或者相邻的元素不相同 if (!i || seen !== sortedArray[i]) { res.push(sortedArray[i]) } seen = sortedArray[i]; } return res; }console.log(unique(array));
Ifソートされた配列の重複を排除します。この方法は、indexOf を使用するより効率が確実に高くなります。
unique API
これら 2 つのメソッドを理解した後、入力された配列が重複しているかどうかを isSorted パラメーターに基づいて判断し、対応する隣接要素が重複しているかどうかを判断します。同じ、 false の場合、indexOf を使用して
var array1 = [1, 2, '1', 2, 1];var array2 = [1, 1, '1', 2, 2];// 第一版function unique(array, isSorted) { var res = []; var seen = []; for (var i = 0, len = array.length; i < len; i++) { var value = array[i]; if (isSorted) { if (!i || seen !== value) { res.push(value) } seen = value; } else if (res.indexOf(value) === -1) { res.push(value); } } return res; }console.log(unique(array1)); // [1, 2, "1"]console.log(unique(array2, true)); // [1, "1", 2]
最適化
を判断します。 unqique はすでに重複排除機能を試すことができますが、この API をより強力にするために、要件を考慮してみましょう:
新しい要件: 文字 上位と下位'a' と 'A' のように、大文字と小文字は一貫しているとみなされます。1 つだけ保持してください。
すべての文字を小文字に変換するなど、最初に配列内のすべてのデータを処理してから、それを独自の関数に渡すことはできますが、配列の処理ループを省略して重複排除に直接進む方法はありますか?ループを中国でやるのはどうですか?この要件を満たしましょう:
var array3 = [1, 1, 'a', 'A', 2, 2];// 第二版// iteratee 英文释义:迭代 重复function unique(array, isSorted, iteratee) { var res = []; var seen = []; for (var i = 0, len = array.length; i < len; i++) { var value = array[i]; var computed = iteratee ? iteratee(value, i, array) : value; if (isSorted) { if (!i || seen !== value) { res.push(value) } seen = value; } else if (iteratee) { if (seen.indexOf(computed) === -1) { seen.push(computed); res.push(value); } } else if (res.indexOf(value) === -1) { res.push(value); } } return res; }console.log(unique(array3, false, function(item){ return typeof item == 'string' ? item.toLowerCase() : item })); // [1, "a", 2]
この実装と最後のバージョンでは、関数は 3 つのパラメーターを渡します:
array: 複製される配列を示し、必須
isSorted: 渡される関数を示します。ソートされている場合、true の場合、より高速な方法で重複排除が行われます
iteratee: 関数を渡して各要素を再計算し、処理結果に基づいて重複排除を行います
ここまで、アイデアに基づいて独自の関数を作成しました。詳細についてはGithubを確認してください。
filter
ES5 は、外側のループを簡素化するために使用できるフィルター メソッドを提供します:
たとえば、indexOf を使用するメソッド:
var array = [1, 2, 1, 1, '1'];function unique(array) { var res = array.filter(function(item, index, array){ return array.indexOf(item) === index; }) return res; }console.log(unique(array));
並べ替えと重複排除のメソッド:
var array = [1, 2, 1, 1, '1'];function unique(array) { return array.concat().sort().filter(function(item, index, array){ return !index || item !== array[index - 1] }) }console.log(unique(array));
オブジェクトのキーと値のペア
重複排除の方法 多くの場合、アンダースコアに続く独自の API を既に作成しましたが、視野を広げるために他のメソッドを見てみましょう:
このメソッドは、配列の値をキーとして保存します。たとえば、Object[value1] = true の場合、別の値を判定する場合、Object[value2] が存在する場合、その値は重複していることを意味します。サンプルコードは以下の通りです。
var array = [1, 2, 1, 1, '1'];function unique(array) { var obj = {}; return array.filter(function(item, index, array){ return obj.hasOwnProperty(item) ? false : (obj[item] = true) }) }console.log(unique(array)); // [1, 2]
1と'1'が異なるので問題があることが分かりますが、このメソッドでは同じ値と判断してしまうためです。したがって、この問題を回避するには、typeof item + item をキー値として使用できます。
var array = [1, 2, 1, 1, '1'];function unique(array) { var obj = {}; return array.filter(function(item, index, array) { return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true) }) }console.log(unique(array)); // [1, 2, "1"]
ES6
ES6 の登場により、重複排除の方法が進歩しました。 Set および Map データ構造を使用します。Set を例に挙げると、ES6 は新しいデータ構造 Set を提供します。配列に似ていますが、メンバーの値は一意であり、重複する値はありません。
体重を減らす準備をしていると感じていますか?バージョンを書いてみましょう:
var array = [1, 2, 1, 1, '1'];function unique(array) { return Array.from(new Set(array)); }console.log(unique(array)); // [1, 2, "1"]
さらに簡略化することもできます:
function unique(array) { return [...new Set(array)]; }
さらに簡略化することもできます:
var unique = (a) => [...new Set(a)]
さらに、Map を使用する場合:
function unique (arr) { const seen = new Map() return arr.filter((a) => !seen.has(a) && seen.set(a, 1)) }
JavaScript の進化
重複排除が確認できます。このメソッドは、元の 14 行のコードから ES6 の 1 行のコードになりました。これは実際に JavaScript 言語が常に改良されていることを示しており、今後の開発はますます効率的になるものと信じています。
特別な型の比較
重複排除の方法はここで終了します。ただし、重複排除の対象となる要素の型は、例の単純な 1 と '1' 以外にも、実際には null、未定義、NaN などさまざまです。それでは、これらの要素について、前の方法の重複排除の結果はどうなるのでしょうか?
その前に、いくつかの例を見てみましょう:
var str1 = '1';var str2 = new String('1');console.log(str1 == str2); // trueconsole.log(str1 === str2); // falseconsole.log(null == null); // trueconsole.log(null === null); // trueconsole.log(undefined == undefined); // trueconsole.log(undefined === undefined); // trueconsole.log(NaN == NaN); // falseconsole.log(NaN === NaN); // falseconsole.log(/a/ == /a/); // falseconsole.log(/a/ === /a/); // falseconsole.log({} == {}); // falseconsole.log({} === {}); // false
それでは、そのような配列の場合
var array = [1, 1, '1', '1', null, null, undefined, undefined, new String('1'), new String('1'), /a/, /a/, NaN, NaN];
上記の重複排除方法の結果はどうなるでしょうか?
特別にリストをコンパイルしました。オブジェクトと NaN の重複排除に焦点を当てています:
メソッド結果の説明
for ループ [1, "1", null, unknown, String, String , /a /, /a/, NaN, NaN] オブジェクトと NaN は重複しません
indexOf [1, "1", null, undefined, String, String, /a/, /a/, NaN, NaN] 对象和 NaN 不去重
sort [/a/, /a/, "1", 1, String, 1, String, NaN, NaN, null, undefined] 对象和 NaN 不去重 数字 1 也不去重
filter + indexOf [1, "1", null, undefined, String, String, /a/, /a/] 对象不去重 NaN 会被忽略掉
filter + sort [/a/, /a/, "1", 1, String, 1, String, NaN, NaN, null, undefined] 对象和 NaN 不去重 数字 1 不去重
优化后的键值对方法 [1, "1", null, undefined, String, /a/, NaN] 全部去重
Set [1, "1", null, undefined, String, String, /a/, /a/, NaN] 对象不去重 NaN 去重
想了解为什么会出现以上的结果,看两个 demo 便能明白:
// demo1var arr = [1, 2, NaN];
arr.indexOf(NaN); // -1
indexOf 底层还是使用 === 进行判断,因为 NaN ==== NaN的结果为 false,所以使用 indexOf 查找不到 NaN 元素
// demo2function unique(array) { return Array.from(new Set(array)); }console.log(unique([NaN, NaN])) // [NaN]
Set 认为尽管 NaN === NaN 为 false,但是这两个元素是重复的。
写在最后
虽然去重的结果有所不同,但更重要的是让我们知道在合适的场景要选择合适的方法。
以上内容就是各种不同的JavaScript数组去重方法,如果大家觉得有用的话赶紧收藏起来吧。
相关推荐:
以上がJavaScript 配列の重複排除方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。