これまでに、次の複雑なデータ構造について学習しました。
オブジェクトは、キー付きコレクションを保存するために使用されます。
配列は、順序付けされたコレクションを格納するために使用されます。
しかし、それだけでは実生活には十分ではありません。そのため、 Map
とSet
も存在します。
Map は、 Object
と同様に、キー付きのデータ項目のコレクションです。ただし、主な違いは、 Map
あらゆるタイプのキーが許可されることです。
メソッドとプロパティは次のとおりです。
new Map()
– マップを作成します。
map.set(key, value)
– キーごとに値を格納します。
map.get(key)
– キーによる値を返します。マップにkey
存在しない場合はundefined
。
map.has(key)
– key
存在する場合はtrue
を返し、そうでない場合はfalse
返します。
map.delete(key)
– キーによって要素 (キー/値のペア) を削除します。
map.clear()
– マップからすべてを削除します。
map.size
– 現在の要素数を返します。
例えば:
let Map = new Map(); マップ.set('1', 'str1'); // 文字列キー マップ.set(1, 'num1'); // 数字キー map.set(true, 'bool1'); // ブール値キー // 通常のオブジェクトを覚えていますか?キーを文字列に変換します // Map は型を保持するため、これら 2 つは異なります。 アラート(map.get(1)); // '数値1' アラート(map.get('1') ); // 'str1' アラート(マップ.サイズ); // 3
ご覧のとおり、オブジェクトとは異なり、キーは文字列に変換されません。どのタイプのキーでも可能です。
map[key]
Map
正しい使用方法ではありません
map[key]
も機能しますが、たとえば、 map[key] = 2
と設定することもできますが、これはmap
プレーンな JavaScript オブジェクトとして扱うため、対応するすべての制限 (文字列/シンボル キーのみなど) を意味します。
したがって、 set
、 get
などのmap
メソッドを使用する必要があります。
Map ではオブジェクトをキーとして使用することもできます。
例えば:
let john = { 名前: "ジョン" }; // ユーザーごとに、訪問回数を保存しましょう visitCountMap = new Map(); にしましょう。 // ジョンはマップのキーです visitCountMap.set(john, 123); alert( visitCountMap.get(john) ); // 123
オブジェクトをキーとして使用することは、最も注目に値する重要なMap
機能の 1 つです。同じことはObject
には当てはまりません。 Object
のキーとして文字列を使用するのは問題ありませんが、別のObject
Object
のキーとして使用することはできません。
試してみましょう:
let john = { 名前: "ジョン" }; let ben = { 名前: "ベン" }; visitCountObj = {}; にします。 // オブジェクトを使用してみます 訪問数オブジェクト[ベン] = 234; // ben オブジェクトをキーとして使用してみます 訪問数Obj[ジョン] = 123; // john オブジェクトをキーとして使用しようとすると、ben オブジェクトが置き換えられます // こう書いてあります! alert( visitCountObj["[object オブジェクト]"] ); // 123
visitsCountObj
オブジェクトであるため、上記のjohn
やben
などのすべてのObject
キーを同じ文字列"[object Object]"
に変換します。決して私たちが望んでいることではありません。
Map
キーを比較する方法
キーの同等性をテストするために、 Map
アルゴリズム SameValueZero を使用します。これは厳密な等価===
とほぼ同じですが、違いはNaN
がNaN
と等しいとみなされることです。したがって、 NaN
もキーとして使用できます。
このアルゴリズムは変更またはカスタマイズできません。
連鎖
すべてのmap.set
呼び出しはマップ自体を返すため、呼び出しを「連鎖」できます。
マップ.set('1', 'str1') .set(1, 'num1') .set(true, 'bool1');
map
をループするには、次の 3 つの方法があります。
map.keys()
– キーの反復可能オブジェクトを返します。
map.values()
– 値の反復可能値を返します。
map.entries()
– エントリ[key, value]
の反復可能値を返します。これはfor..of
でデフォルトで使用されます。
例えば:
let RecipeMap = new Map([ ['キュウリ', 500], [「トマト」、350]、 [「タマネギ」、50] ]); // キー (野菜) を反復処理します for (recipeMap.keys()の野菜を作る) { アラート(野菜); // キュウリ、トマト、タマネギ } // 値 (金額) を反復処理します。 for (recipeMap.values() の量を許可) { アラート(金額); // 500、350、50 } // [キー、値] エントリを反復処理します。 for (recipeMap のエントリを入力) { // RecipeMap.entries() と同じ アラート(エントリ); // キュウリ、500 (など) }
広告掲載オーダーが使用されます
反復は、値が挿入されたのと同じ順序で行われます。通常のObject
とは異なり、 Map
この順序を保持します。
それに加えて、 Map
Array
と同様の組み込みのforEach
メソッドがあります。
// (キー、値) ペアごとに関数を実行します RecipeMap.forEach( (値, キー, マップ) => { アラート(`${キー}: ${値}`); // キュウリ: 500 など });
Map
が作成されると、次のように、初期化のためにキーと値のペアを持つ配列 (または別の反復可能オブジェクト) を渡すことができます。
// [キー、値] ペアの配列 let map = new Map([ ['1', 'str1'], [1, 'num1'], [true、'bool1'] ]); アラート(map.get('1') ); // str1
プレーン オブジェクトがあり、そこからMap
を作成したい場合は、その形式でオブジェクトのキーと値のペアの配列を返す組み込みメソッド Object.entries(obj) を使用できます。
したがって、次のようにオブジェクトからマップを作成できます。
obj = { にします 名前:「ジョン」、 年齢: 30歳 }; let map = new Map(Object.entries(obj)); alert(map.get('name') ); // ジョン
ここで、 Object.entries
キーと値のペアの配列[ ["name","John"], ["age", 30] ]
を返します。それがMap
必要なことです。
Object.entries(obj)
を使用してプレーン オブジェクトからMap
を作成する方法を見てきました。
逆の処理を行うObject.fromEntries
メソッドがあります。 [key, value]
ペアの配列が与えられると、それらからオブジェクトを作成します。
let 価格 = Object.fromEntries([ ['バナナ', 1], ['オレンジ', 2], [「肉」、4] ]); // 現在の価格 = { バナナ: 1、オレンジ: 2、肉: 4 } アラート(価格.オレンジ); // 2
Object.fromEntries
使用してMap
からプレーン オブジェクトを取得できます。
たとえば、データをMap
に保存しますが、プレーン オブジェクトを期待するサードパーティのコードにデータを渡す必要があります。
さぁ行こう:
let Map = new Map(); マップ.set('バナナ', 1); マップ.set('オレンジ', 2); マップ.set('肉', 4); let obj = Object.fromEntries(map.entries()); // プレーンなオブジェクトを作成します (*) // 終わり! // obj = { バナナ: 1、オレンジ: 2、肉: 4 } アラート(obj.orange); // 2
map.entries()
を呼び出すと、 Object.fromEntries
に正確に正しい形式で、キーと値のペアの反復可能値が返されます。
行(*)
を短くすることもできます。
let obj = Object.fromEntries(map); // .entries() を省略
Object.fromEntries
引数として反復可能なオブジェクトを期待しているため、これも同じです。必ずしも配列である必要はありません。そして、 map
の標準的な反復は、 map.entries()
と同じキー/値のペアを返します。したがって、 map
と同じキー/値を持つプレーンなオブジェクトを取得します。
Set
は特別なタイプのコレクション、つまり「値のセット」(キーなし) であり、各値は 1 回だけ出現します。
その主な方法は次のとおりです。
new Set([iterable])
– セットを作成し、 iterable
オブジェクト (通常は配列) が提供されている場合は、そこから値をセットにコピーします。
set.add(value)
– 値を追加し、セット自体を返します。
set.delete(value)
– 値を削除し、呼び出しの時点でvalue
存在する場合はtrue
を返し、それ以外の場合はfalse
返します。
set.has(value)
– セット内に値が存在する場合はtrue
を返し、それ以外の場合はfalse
返します。
set.clear()
– セットからすべてを削除します。
set.size
– 要素数です。
主な特徴は、同じ値を指定してset.add(value)
を繰り返し呼び出しても何も行わないことです。これが、各値がSet
内に 1 回だけ出現する理由です。
たとえば、訪問者が来るので、全員のことを覚えておきたいと思います。ただし、繰り返しアクセスしても重複が発生することはありません。訪問者は 1 回だけ「カウント」される必要があります。
Set
まさにそれに適しています。
let set = new Set(); let john = { 名前: "ジョン" }; let ピート = { 名前: "ピート" }; メアリー = { 名前: "メアリー" }; // 訪問、一部のユーザーは複数回訪問します set.add(ジョン); set.add(ピート); set.add(メアリー); set.add(ジョン); set.add(メアリー); // set は一意の値のみを保持します アラート( set.size ); // 3 for (ユーザーにセットを許可) { アラート(ユーザー名); // ジョン (その後、ピートとメアリー) }
Set
の代わりに、ユーザーの配列を使用し、arr.find を使用して挿入のたびに重複をチェックするコードを使用することもできます。ただし、このメソッドは配列全体を調べてすべての要素をチェックするため、パフォーマンスは大幅に低下します。 Set
、一意性チェックのために内部的により適切に最適化されています。
for..of
またはforEach
を使用してセットをループできます。
let set = new Set(["オレンジ", "リンゴ", "バナナ"]); for (セットの値を設定)alert(value); // forEach も同様: set.forEach((value, valueAgain, set) => { アラート(値); });
面白いことに注意してください。 forEach
に渡されるコールバック関数には、 value
、同じ値valueAgain
、そしてターゲット オブジェクトの 3 つの引数があります。実際、同じ値が引数に 2 回現れます。
これは、 forEach
渡されるコールバックに 3 つの引数があるMap
との互換性のためです。確かに少し奇妙に見えます。ただし、これにより、場合によってはMap
Set
に簡単に置き換えたり、その逆を行うことができます。
Map
反復子に対して持つのと同じメソッドもサポートされています。
set.keys()
– 値の反復可能なオブジェクトを返します。
set.values()
– set.keys()
と同じ、 Map
との互換性のため、
set.entries()
– エントリ[value, value]
の反復可能なオブジェクトを返します。 Map
との互換性のために存在します。
Map
– キー付きの値のコレクションです。
メソッドとプロパティ:
new Map([iterable])
– 初期化のための[key,value]
ペアのオプションのiterable
(配列など) を使用してマップを作成します。
map.set(key, value)
– キーごとに値を格納し、マップ自体を返します。
map.get(key)
– キーによる値を返します。マップにkey
存在しない場合はundefined
。
map.has(key)
– key
存在する場合はtrue
を返し、そうでない場合はfalse
返します。
map.delete(key)
– キーによって要素を削除し、呼び出しの時点でkey
存在していた場合はtrue
返し、それ以外の場合はfalse
返します。
map.clear()
– マップからすべてを削除します。
map.size
– 現在の要素数を返します。
通常のObject
との違い:
任意のキー、オブジェクトをキーにすることができます。
追加の便利なメソッド、 size
プロパティ。
Set
– 一意の値のコレクションです。
メソッドとプロパティ:
new Set([iterable])
– 初期化用の値のオプションのiterable
(配列など) を使用してセットを作成します。
set.add(value)
– 値を追加し ( value
存在する場合は何もしません)、セット自体を返します。
set.delete(value)
– 値を削除し、呼び出しの時点でvalue
存在する場合はtrue
を返し、それ以外の場合はfalse
返します。
set.has(value)
– セット内に値が存在する場合はtrue
を返し、それ以外の場合はfalse
返します。
set.clear()
– セットからすべてを削除します。
set.size
– 要素数です。
Map
とSet
反復は常に挿入順序に従って行われるため、これらのコレクションが順序付けされていないとは言えませんが、要素を並べ替えたり、番号によって要素を直接取得したりすることはできません。
重要度: 5
arr
配列とします。
arr
の一意の項目を含む配列を返す関数unique(arr)
を作成します。
例えば:
関数 unique(arr) { /* あなたのコード */ } let 値 = ["ハレ", "クリシュナ", "ハレ", "クリシュナ", 「クリシュナ」、「クリシュナ」、「ハレ」、「ハレ」、「:-O」 ]; alert( unique(values) ); // ハレ、クリシュナ、 :-O
PS ここでは文字列が使用されていますが、任意の型の値を使用できます。
PPS 一意の値を保存するにはSet
を使用します。
テストを含むサンドボックスを開きます。
関数 unique(arr) { return Array.from(new Set(arr)); }
サンドボックス内のテストを含むソリューションを開きます。
重要度: 4
アナグラムは、同じ文字が同じ数だけ含まれているが、順序が異なる単語です。
例えば:
昼寝 - パン イヤーアール時代 詐欺師 - ヘクタール - 教師
アナグラムからクリーンアップされた配列を返す関数aclean(arr)
を作成します。
例えば:
let arr = [「昼寝」、「教師」、「詐欺師」、「PAN」、「耳」、「時代」、「ヘクタール」]; アラート( aclean(arr) ); // "昼寝,教師,耳" または "PAN,詐欺師,時代"
どのアナグラム グループであっても、1 つの単語だけを残す必要があります。
テストを含むサンドボックスを開きます。
すべてのアナグラムを見つけるには、すべての単語を文字に分割して並べ替えましょう。文字で並べ替えると、すべてのアナグラムは同じになります。
例えば:
昼寝、パン -> アンプ 耳、時代、アレ -> aer 詐欺師、ヘクタール、教師 -> aceehrst ...
文字でソートされたバリアントをマップ キーとして使用し、各キーごとに 1 つの値のみを保存します。
関数 aclean(arr) { let Map = new Map(); for (arr の言葉を聞かせてください) { // 単語を文字ごとに分割し、並べ替えて結合し直します letsorted = word.toLowerCase().split('').sort().join(''); // (*) map.set(ソート済み、ワード); } Array.from(map.values()) を返します。 } let arr = [「昼寝」、「教師」、「詐欺師」、「PAN」、「耳」、「時代」、「ヘクタール」]; アラート( aclean(arr) );
文字の並べ替えは、行(*)
内の一連の呼び出しによって行われます。
便宜上、複数の行に分割しましょう。
letsorted = word // PAN .toLowerCase() // パン .split('') // ['p','a','n'] .sort() // ['a','n','p'] 。参加する(''); // アンプ
2 つの異なる単語'PAN'
と'nap'
は、同じ文字ソート形式'anp'
を受け取ります。
次の行では、単語をマップに追加します。
map.set(ソート済み、ワード);
同じ文字ソート形式の単語に再び遭遇すると、マップ内の同じキーで前の値が上書きされます。したがって、文字形式ごとに常に最大 1 つの単語が存在します。
最後にArray.from(map.values())
反復可能なマップ値を取得し (結果にキーは必要ありません)、それらの配列を返します。
ここでは、キーは文字列であるため、 Map
代わりにプレーン オブジェクトを使用することもできます。
解決策は次のようになります。
関数 aclean(arr) { obj = {} にします。 for (let i = 0; i < arr.length; i++) { letsorted = arr[i].toLowerCase().split("").sort().join(""); obj[ソート済み] = arr[i]; } 戻り値 Object.values(obj); } let arr = [「昼寝」、「教師」、「詐欺師」、「PAN」、「耳」、「時代」、「ヘクタール」]; アラート( aclean(arr) );
サンドボックス内のテストを含むソリューションを開きます。
重要度: 5
変数内のmap.keys()
の配列を取得し、それに配列固有のメソッド ( .push
など) を適用したいと考えています。
しかし、それはうまくいきません:
let Map = new Map(); map.set("名前", "ジョン"); let キー = マップ.keys(); // エラー: key.push は関数ではありません key.push("もっと");
なぜ? keys.push
が機能するようにコードを修正するにはどうすればよいでしょうか?
これは、 map.keys()
配列ではなく反復可能を返すためです。
Array.from
使用して配列に変換できます。
let Map = new Map(); map.set("名前", "ジョン"); let キー = Array.from(map.keys()); key.push("もっと"); アラート(キー); // 名前など