MochiuWiki : SUSE, EC, PCB
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
JavaScriptの基礎 - 配列のソートと変換のソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
JavaScriptの基礎 - 配列のソートと変換
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == JavaScriptの配列には、要素の順序を変更するためのソートメソッドや、配列の形状を変換するためのメソッドが豊富に用意されている。<br> これらを活用することで、データの並び替え、構造変換、文字列への変換といった処理を簡潔に記述できる。<br> <br> <code>sort()</code> は配列を破壊的にソートするメソッドであり、デフォルトでは要素をUnicodeコードポイント順に並べる。<br> 数値のソートや文字列の言語特有の順序を扱う場合は、比較関数を明示的に指定する必要がある。<br> <br> ES2023では、<code>sort()</code> や <code>reverse()</code> の非破壊版にあたる <code>toSorted()</code>・<code>toReversed()</code>・<code>toSpliced()</code>・<code>with()</code> が追加された。<br> これらのメソッドは元の配列を変更せず新しい配列を返すため、Reactの状態管理のようなイミュータブルな更新パターンとの相性が良い。<br> <br> <code>flat()</code> はネストした配列を平坦化するメソッドであり、<code>Array.from()</code> はイテラブルや配列風オブジェクトから新しい配列を生成する汎用的なメソッドである。<br> <code>join()</code> や <code>concat()</code> は配列を文字列や他の配列と組み合わせるための変換メソッドである。<br> <br> また、<code>Array.isArray()</code> は値が配列かどうかを確実に判定する静的メソッドであり、<code>typeof</code> や <code>instanceof</code> が抱える問題を回避できる。<br> <br><br> == sort == <code>sort()</code> は配列の要素をソートするメソッドである。<br> 元の配列を直接変更する破壊的なメソッドであり、戻り値はソート後の元の配列への参照である。<br> <br> ==== デフォルトの動作と注意点 ==== 比較関数を指定しない場合、<code>sort()</code> は全ての要素を文字列に変換した上で、UNICODEコードポイント順に並べる。<br> この動作は文字列の配列に対しては概ね期待通りに動作するが、数値の配列に対しては意図しない結果になることがある。<br> <br> <syntaxhighlight lang="javascript"> // 文字列配列のソート const fruits = ["banana", "apple", "cherry"]; fruits.sort(); console.log(fruits); // ["apple", "banana", "cherry"] // 注意 : 数値配列でのデフォルトの動作 const numbers = [10, 9, 80, 1, 5]; numbers.sort(); console.log(numbers); // [1, 10, 5, 80, 9] (文字列として比較されるため意図しない順序になる) </syntaxhighlight> <br> <u>数値配列をソートするには、比較関数を明示的に指定する必要がある。</u><br> <br> ==== 比較関数 ==== <code>sort()</code> に比較関数を渡すことで、任意のソート順序を定義できる。<br> 比較関数は2つの引数 <code>a</code> と <code>b</code> を受け取り、以下の規則に従って数値を返す必要がある。<br> <br> <center> {| class="wikitable" |+ 比較関数の戻り値の規則 ! 戻り値 !! 意味 |- | 負の値 || aをbより前に配置する |- | 0 || a と b の順序を変更しない |- | 正の値 || aをbより後に配置する |} </center> <br> ==== 数値のソート ==== <u>数値配列を正しくソートするには、比較関数として <code>(a, b) => a - b</code> (昇順) または <code>(a, b) => b - a</code> (降順) を使用する。</u><br> <br> <u>なお、<code>sort()</code> は破壊的なメソッドであるため、元の配列を保持したい場合はスプレッド構文 <code>[...numbers]</code> でコピーしてからソートする。</u><br> <br> <syntaxhighlight lang="javascript"> const numbers = [10, 9, 80, 1, 5]; // 昇順ソート const ascending = [...numbers].sort((a, b) => a - b); console.log(ascending); // [1, 5, 9, 10, 80] // 降順ソート const descending = [...numbers].sort((a, b) => b - a); console.log(descending); // [80, 10, 9, 5, 1] </syntaxhighlight> <br> ==== 文字列のソート (localeCompare) ==== 日本語や他の言語を含む文字列配列を正しくソートするには、<code>localeCompare()</code> を使用する。<br> <code>localeCompare()</code> は言語特有の文字順序を考慮した比較を行う。<br> <br> <syntaxhighlight lang="javascript"> // 通常の比較では日本語のソートが不正確になる場合がある const items = ["東京", "大阪", "名古屋", "札幌"]; items.sort((a, b) => a.localeCompare(b, "ja")); console.log(items); // ロケール順に並んだ結果 // アルファベットの大文字・小文字を区別しないソート const words = ["Banana", "apple", "Cherry"]; words.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" })); console.log(words); // ["apple", "Banana", "Cherry"] </syntaxhighlight> <br> ==== オブジェクト配列のソート ==== オブジェクトの配列をソートするには、比較関数内でソートの基準にするプロパティを参照する。<br> <br> <u>ES2019以降、<code>sort()</code> は安定ソート (同じ比較結果の要素の元の順序を保持する) が仕様として保証されている。</u><br> <br> <syntaxhighlight lang="javascript"> const users = [ { name: "Alice", age: 30 }, { name: "Bob", age: 25 }, { name: "Carol", age: 35 } ]; // ageプロパティで昇順ソート users.sort((a, b) => a.age - b.age); console.log(users); // [{ name: "Bob", age: 25 }, { name: "Alice", age: 30 }, { name: "Carol", age: 35 }] // nameプロパティでアルファベット順ソート users.sort((a, b) => a.name.localeCompare(b.name)); console.log(users); // [{ name: "Alice", age: 30 }, { name: "Bob", age: 25 }, { name: "Carol", age: 35 }] </syntaxhighlight> <br><br> == reverse == <code>reverse()</code> は配列の要素の順序を反転するメソッドである。<br> <code>sort()</code> と同様に破壊的なメソッドであり、元の配列を直接変更する。<br> <br> 戻り値は反転後の元の配列への参照である。<br> <br> <syntaxhighlight lang="javascript"> const arr = [1, 2, 3, 4, 5]; // reverseは元の配列を変更する const reversed = arr.reverse(); console.log(arr); // [5, 4, 3, 2, 1] (元の配列が変更される) console.log(reversed === arr); // true (戻り値は元の配列への参照) // 元の配列を保持したい場合はコピーしてから操作する const original = [1, 2, 3, 4, 5]; const copy = [...original].reverse(); console.log(original); // [1, 2, 3, 4, 5] (変更されない) console.log(copy); // [5, 4, 3, 2, 1] // sort()と組み合わせて降順ソートを実現する例 const numbers = [3, 1, 4, 1, 5, 9]; const sortedDesc = [...numbers].sort((a, b) => a - b).reverse(); console.log(sortedDesc); // [9, 5, 4, 3, 1, 1] </syntaxhighlight> <br><br> == ES2023の非破壊メソッド == ES2023では、破壊的な配列メソッドに対応する非破壊版が導入された。<br> これらのメソッドは元の配列を変更せず、新しい配列を返す。<br> <br> ReactやVue等のフレームワークでは、状態 (state) をイミュータブルに更新することが推奨されている。<br> 従来は、<code>[...state].sort(...)</code> のようにスプレッド構文で配列をコピーしてから操作する必要があったが、これらのメソッドを使用することでより簡潔に記述できる。<br> <br> Webブラウザ対応状況を以下に示す。<br> * Chrome / Edge 110以降 * Safari 16以降 * Firefox 115以降 * Node.js 20以降 <br> ==== toSorted ==== <code>toSorted(compareFn)</code> は <code>sort()</code> の非破壊版である。<br> 元の配列を変更せず、ソート済みの新しい配列を返す。<br> <br> <syntaxhighlight lang="javascript"> const numbers = [3, 1, 4, 1, 5, 9]; // toSortedは元の配列を変更しない const sorted = numbers.toSorted((a, b) => a - b); console.log(numbers); // [3, 1, 4, 1, 5, 9] (変更されない) console.log(sorted); // [1, 1, 3, 4, 5, 9] // Reactの状態管理での活用例 // 従来の方法 // setState(prevState => [...prevState].sort((a, b) => a - b)); // toSortedを使用した方法 // setState(prevState => prevState.toSorted((a, b) => a - b)); </syntaxhighlight> <br> ==== toReversed ==== <code>toReversed()</code> は <code>reverse()</code> の非破壊版である。<br> 元の配列を変更せず、逆順の新しい配列を返す。<br> <br> <syntaxhighlight lang="javascript"> const arr = [1, 2, 3, 4, 5]; // toReversedは元の配列を変更しない const reversed = arr.toReversed(); console.log(arr); // [1, 2, 3, 4, 5] (変更されない) console.log(reversed); // [5, 4, 3, 2, 1] </syntaxhighlight> <br> ==== toSpliced ==== <code>toSpliced(start, deleteCount, ...items)</code> は <code>splice()</code> の非破壊版である。<br> 元の配列を変更せず、指定した位置の要素を削除・置換・追加した新しい配列を返す。<br> <br> <syntaxhighlight lang="javascript"> const arr = ["a", "b", "c", "d", "e"]; // 要素の削除 (インデックス1から2要素削除) const deleted = arr.toSpliced(1, 2); console.log(arr); // ["a", "b", "c", "d", "e"] (変更されない) console.log(deleted); // ["a", "d", "e"] // 要素の置換 (インデックス2の要素を "X", "Y" に置換) const replaced = arr.toSpliced(2, 1, "X", "Y"); console.log(replaced); // ["a", "b", "X", "Y", "d", "e"] // 要素の追加 (インデックス2に "X" を挿入) const inserted = arr.toSpliced(2, 0, "X"); console.log(inserted); // ["a", "b", "X", "c", "d", "e"] </syntaxhighlight> <br> ==== with ==== <code>with(index, value)</code> は、指定したインデックスの要素を新しい値に置き換えた新しい配列を返す。<br> 元の配列は変更されない。<br> 負のインデックスを使用して末尾からの位置を指定することもできる。<br> <br> <syntaxhighlight lang="javascript"> const arr = [1, 2, 3, 4, 5]; // インデックス2の要素を99に置き換える const updated = arr.with(2, 99); console.log(arr); // [1, 2, 3, 4, 5] (変更されない) console.log(updated); // [1, 2, 99, 4, 5] // 負のインデックスも使用可能 const last = arr.with(-1, 100); console.log(last); // [1, 2, 3, 4, 100] // Reactの状態管理でのイミュータブルな更新例 // 従来の方法 // setState(prevState => prevState.map((item, i) => i === index ? newValue : item)); // withを使用した方法 // setState(prevState => prevState.with(index, newValue)); </syntaxhighlight> <br><br> == flat == <code>flat(depth)</code> は、ネストした配列を指定した深さまで平坦化した新しい配列を返す。<br> 元の配列は変更されない非破壊的なメソッドである。<br> <br> <syntaxhighlight lang="javascript"> const nested = [1, [2, 3], [4, [5, 6]]]; // デフォルトは1段階のみ平坦化 console.log(nested.flat()); // [1, 2, 3, 4, [5, 6]] // 深さを指定して平坦化 console.log(nested.flat(2)); // [1, 2, 3, 4, 5, 6] // Infinity で全ての深さを平坦化 const deepNested = [1, [2, [3, [4, [5]]]]]; console.log(deepNested.flat(Infinity)); // [1, 2, 3, 4, 5] // 空要素の除去にも使用できる const sparse = [1, , 2, , 3]; console.log(sparse.flat()); // [1, 2, 3] </syntaxhighlight> <br> <code>flatMap(fn)</code> は <code>map()</code> と <code>flat(1)</code> を組み合わせたメソッドである。<br> 各要素にマッピング関数を適用した後に1段階だけ平坦化した新しい配列を返す。<br> <br> <syntaxhighlight lang="javascript"> const sentences = ["Hello World", "Foo Bar"]; // mapとflatを組み合わせた場合 const words1 = sentences.map(s => s.split(" ")).flat(); console.log(words1); // ["Hello", "World", "Foo", "Bar"] // flatMapを使用した場合 (同じ結果を簡潔に記述) const words2 = sentences.flatMap(s => s.split(" ")); console.log(words2); // ["Hello", "World", "Foo", "Bar"] // 条件により要素数を変えるフィルタリングと変換の組み合わせ const numbers = [1, 2, 3, 4, 5]; const result = numbers.flatMap(n => n % 2 === 0 ? [n, n * 2] : []); console.log(result); // [2, 4, 4, 8] </syntaxhighlight> <br><br> == Array.from == <code>Array.from()</code> は、イテラブルオブジェクトまたは配列風オブジェクトから新しい配列を生成する静的メソッドである。<br> <br> ==== 基本的な使用方法 ==== <code>Array.from()</code> は以下のような入力から配列を生成できる。<br> <br> <syntaxhighlight lang="javascript"> // 文字列から配列を生成 (イテラブル) console.log(Array.from("Hello")); // ["H", "e", "l", "l", "o"] // Setから配列を生成 (重複排除に活用) const set = new Set([1, 2, 2, 3, 3]); console.log(Array.from(set)); // [1, 2, 3] // Mapから配列を生成 const map = new Map([["a", 1], ["b", 2]]); console.log(Array.from(map)); // [["a", 1], ["b", 2]] // NodeList (DOMのquerySelectorAll等) から配列を生成 // const nodeList = document.querySelectorAll("div"); // const divArray = Array.from(nodeList); // 配列風オブジェクト (lengthプロパティを持つオブジェクト) から配列を生成 const arrayLike = { 0: "a", 1: "b", 2: "c", length: 3 }; console.log(Array.from(arrayLike)); // ["a", "b", "c"] </syntaxhighlight> <br> ==== 第2引数のマッピング関数 ==== <code>Array.from()</code> の第2引数にマッピング関数を渡すことで、配列生成と同時に要素を変換できる。<br> <br> <code>Array.from({length: n}, fn)</code> のパターンは、連番配列や特定のパターンを持つ配列を生成する際に広く使われる。<br> <br> <syntaxhighlight lang="javascript"> // 0から4までの連番配列を生成 const range = Array.from({ length: 5 }, (_, i) => i); console.log(range); // [0, 1, 2, 3, 4] // 1から5までの連番配列を生成 const range1to5 = Array.from({ length: 5 }, (_, i) => i + 1); console.log(range1to5); // [1, 2, 3, 4, 5] // 文字列配列を変換しながら生成 const doubled = Array.from([1, 2, 3], x => x * 2); console.log(doubled); // [2, 4, 6] // 二次元配列の生成 const matrix = Array.from({ length: 3 }, (_, i) => Array.from({ length: 3 }, (_, j) => i * 3 + j + 1) ); console.log(matrix); // [[1, 2, 3], [4, 5, 6], [7, 8, 9]] </syntaxhighlight> <br><br> == Array.isArray == <code>Array.isArray(value)</code> は、引数が配列かどうかを判定する静的メソッドである。<br> <br> 配列であれば <code>true</code>、そうでなければ <code>false</code> を返す。<br> <br> <syntaxhighlight lang="javascript"> // 配列の判定 console.log(Array.isArray([1, 2, 3])); // true console.log(Array.isArray([])); // true // 配列でないものの判定 console.log(Array.isArray("string")); // false console.log(Array.isArray(123)); // false console.log(Array.isArray({})); // false console.log(Array.isArray(null)); // false console.log(Array.isArray(undefined)); // false </syntaxhighlight> <br> 下表に、<code>typeof</code> 演算子や <code>instanceof</code> 演算子を使用した判定と比較した場合の違いを示す。<br> <br> <center> {| class="wikitable" |+ 配列判定方法の比較 ! 方法 !! 結果の例 !! 問題点 |- | <code>typeof []</code> || <code>"object"</code> を返す || 配列かオブジェクトかを区別できない。 |- | <code>[] instanceof Array</code> || <code>true</code> を返す || iframe等のクロスフレーム環境で失敗することがある。 |- | <code>Array.isArray([])</code> || <code>true</code> を返す || 全てのコンテキストで正確に動作する。 |} </center> <br> <u><code>Array.isArray()</code> はどの実行コンテキストでも正確に動作するため、配列の判定には <code>Array.isArray()</code> を使用することを推奨する。</u><br> <br><br> == join と toString == <code>join(separator)</code> は、配列の全要素を結合して1つの文字列にするメソッドである。<br> 引数として区切り文字を指定でき、省略した場合はカンマ (<code>,</code>) が使用される。<br> <br> <code>null</code> や <code>undefined</code> の要素は空文字列として扱われる。<br> <br> <syntaxhighlight lang="javascript"> const fruits = ["apple", "banana", "cherry"]; // デフォルトはカンマ区切り console.log(fruits.join()); // "apple,banana,cherry" // 区切り文字を指定 console.log(fruits.join(", ")); // "apple, banana, cherry" console.log(fruits.join(" - "));// "apple - banana - cherry" console.log(fruits.join("")); // "applebananacherry" // null / undefinedは空文字列として扱われる const mixed = ["a", null, "b", undefined, "c"]; console.log(mixed.join("-")); // "a--b--c" // 数値の配列をCSV形式に変換する例 const numbers = [1, 2, 3, 4, 5]; console.log(numbers.join(",")); // "1,2,3,4,5" </syntaxhighlight> <br> <code>toString()</code> は配列をカンマ区切りの文字列に変換するメソッドである。<br> 引数無しの <code>join()</code> と同等の結果を返す。<br> <br> <syntaxhighlight lang="javascript"> const arr = [1, 2, 3]; console.log(arr.toString()); // "1,2,3" console.log(arr.join(",")); // "1,2,3" (同等の結果) // 文字列への暗黙的な変換でもtoString()が呼ばれる console.log("array: " + arr); // "array: 1,2,3" </syntaxhighlight> <br><br> == concat == <code>concat(...values)</code> は、元の配列に引数の配列や値を結合した新しい配列を返す非破壊的なメソッドである。<br> <br> 複数の配列や値を一度に結合することができる。<br> <br> <syntaxhighlight lang="javascript"> const arr1 = [1, 2, 3]; const arr2 = [4, 5, 6]; const arr3 = [7, 8, 9]; // 2つの配列を結合 const combined = arr1.concat(arr2); console.log(combined); // [1, 2, 3, 4, 5, 6] console.log(arr1); // [1, 2, 3] (変更されない) // 複数の配列を一度に結合 const all = arr1.concat(arr2, arr3); console.log(all); // [1, 2, 3, 4, 5, 6, 7, 8, 9] // 配列と値を混在させて結合 const mixed = arr1.concat(4, 5, arr3); console.log(mixed); // [1, 2, 3, 4, 5, 7, 8, 9] </syntaxhighlight> <br> スプレッド構文 <code>[...arr1, ...arr2]</code> を使用した場合と比較すると、結果は同等であるが記法が異なる。<br> <br> <syntaxhighlight lang="javascript"> const arr1 = [1, 2, 3]; const arr2 = [4, 5, 6]; // concatを使用した場合 const result1 = arr1.concat(arr2); // スプレッド構文を使用した場合 (同等の結果) const result2 = [...arr1, ...arr2]; console.log(result1); // [1, 2, 3, 4, 5, 6] console.log(result2); // [1, 2, 3, 4, 5, 6] // スプレッド構文は途中に要素を挿入する際に柔軟 const result3 = [...arr1, 99, ...arr2]; console.log(result3); // [1, 2, 3, 99, 4, 5, 6] </syntaxhighlight> <br><br> == 関連情報 == * [[JavaScriptの基礎 - 配列の操作]] *: 配列の作成、要素へのアクセス、追加・削除、検索メソッド * [[JavaScriptの基礎 - 配列の反復メソッド]] *: forEach, map, filter, reduce等の反復処理メソッド * [[JavaScriptの基礎 - 文字列]] *: 文字列の操作メソッドと基本的な使い方 <br><br> {{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux |image=/resources/assets/MochiuLogo_Single_Blue.png }} __FORCETOC__ [[カテゴリ:Web]]
JavaScriptの基礎 - 配列のソートと変換
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse