🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

810閲覧

特別な条件の並べ替え。

tkshp

総合スコア174

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2019/12/04 14:42

編集2019/12/09 02:02

前提・実現したいこと

下記のコードのような配列を、コメントのように並び変えたいのですが、
どういったコードを組めばよいでしょうか?
やり方によっては、かなり冗長なコードになってしまいそうなので、効率的な書き方を考えています。
ご教示お願いします。

JavaScript

1//要素の並び順が、 2//オブジェクトのgradeのアルファベットの昇順で優先に並べられていて、 3//gradeごとにnumberが昇順の配列。 4//要素は、gradeとnumberを持つ任意のオブジェクトで、 5//上記の並び順だけが保証されている。 6var objArray = [ 7 { grade: 'A', number: 2 }, 8 { grade: 'A', number: 3 }, 9 { grade: 'B', number: 1 }, 10 { grade: 'B', number: 2 }, 11 { grade: 'S', number: 1 }, 12 { grade: 'S', number: 2 } 13]; 14 15//目的の並び替え。 16//gradeでSだけをトップに持ってきて、 17//以降のgradeはアルファベットの昇順のままとなる。 18//gradeごとにnumberが昇順であることも保たれている。 19// var objArray = [ 20// { grade: 'S', number: 1 }, 21// { grade: 'S', number: 2 }, 22// { grade: 'A', number: 2 }, 23// { grade: 'A', number: 3 }, 24// { grade: 'B', number: 1 }, 25// { grade: 'B', number: 2 }, 26// ]; 27

試したこと

イメージ的には、下記のようなwhile文の書き方がスマートな気がするのですが、
条件で代入はできないのでしょうか?
構文エラーになってしまいます。

JavaScript

1//要素の並び順が、 2//オブジェクトのgradeのアルファベットの昇順で優先に並べられていて、 3//gradeごとにnumberが昇順の配列。 4//要素は、gradeとnumberを持つ任意のオブジェクトで、 5//上記の並び順だけが保証されている。 6var objArray = [ 7 { grade: 'A', number: 2 }, 8 { grade: 'A', number: 3 }, 9 { grade: 'B', number: 1 }, 10 { grade: 'B', number: 2 }, 11 { grade: 'S', number: 1 }, 12 { grade: 'S', number: 2 } 13]; 14 15while((var sValue = objArray.pop["grade"]) == "S"){ 16 objArray.unshift(sValue); 17} 18 19//目的の並び替え。 20//gradeでSだけをトップに持ってきて、 21//以降のgradeはアルファベットの昇順のままとなる。 22//gradeごとにnumberが昇順であることも保たれている。 23// var objArray = [ 24// { grade: 'S', number: 1 }, 25// { grade: 'S', number: 2 }, 26// { grade: 'A', number: 2 }, 27// { grade: 'A', number: 3 }, 28// { grade: 'B', number: 1 }, 29// { grade: 'B', number: 2 }, 30// ]; 31

エラーメッセージ。

while((var sValue = objArray.pop["grade"]) == "S"){ ^^^ SyntaxError: Unexpected token var

さらに考えたのですが、この書き方だと代入できたとしても、
sValueにオブジェクトじゃなくて、gradeの値が入ってしまうことに気づきました。
このようなイメージでコードを組むことは可能ですか?
もしくはもっと簡潔な組み方はありますか?
ご教示お願いします。

追記 VSCodeでデバッグを繰り返すと、並び順が変わる問題について。

VSCodeでデバッグを繰り返すと、何故か並び順がたまに変わるという現象が起きました。
VSCodeのデバッグでは、
console.log(objArray);
では、要素のオブジェクトがObjectと表示されるだけで、オブジェクトの中身まで表示されないので、
forEachで回して表示させるようにしました。

JavaScript

1 var objArray = [ 2 { grade: 'B', number: 2 }, 3 { grade: 'S', number: 2 }, 4 { grade: 'A', number: 2 }, 5 { grade: 'A', number: 3 }, 6 { grade: 'B', number: 1 }, 7 { grade: 'S', number: 1 }, 8 ]; 9 10const compare = (a, b) => { 11 12 if (a.grade !== b.grade) { 13 if (a.grade === 'S') return -1; 14 if (b.grade === 'S') return 1; 15 return a.grade.localeCompare(b.grade); 16 } 17 18 return a.number - b.number; 19}; 20 21objArray.sort(compare); 22 23//console.log(objArray); 24 25objArray.forEach(function( value ) { 26 console.log( value ); 27});

上記をデバッグすると、基本的には下記出力となるのですが、

Object {grade: "S", number: 1} Object {grade: "S", number: 2} Object {grade: "A", number: 2} Object {grade: "A", number: 3} Object {grade: "B", number: 1} Object {grade: "B", number: 2}

しかし、デバッグを繰り返すと、下記のような出力になることもあります。

Object {grade: "S", number: 1} Object {grade: "S", number: 2} Object {grade: "B", number: 1} Object {grade: "A", number: 2} Object {grade: "B", number: 2} Object {grade: "A", number: 3}

下記のようになったりもしました。

Object {grade: "S", number: 1} Object {grade: "S", number: 2} Object {grade: "A", number: 2} Object {grade: "B", number: 1} Object {grade: "A", number: 3} Object {grade: "B", number: 2}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

JavaScript

1var grade = ['S','A','B']; 2var array = [{grade:'A',number:2},{grade:'A',number:3},{grade:'B',number:1},{grade:'B',number:2},{grade:'S',number:1},{grade:'S',number:2}]; 3 4array.sort((a,b) => (grade.indexOf(a.grade) - grade.indexOf(b.grade) || a.number - b.number)); 5console.log(array);

Re: tkshp さん

投稿2019/12/04 15:03

think49

総合スコア18189

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/12/04 15:26

const h = {S:0, A:1, B:2}; objArray.sort ((a, b) => h[a.grade] - h[b.grade] || a.number - b.number);
tkshp

2019/12/05 01:14

ご回答ありがとうございます。 ベストアンサー迷いましたが、私のwhileのイメージの疑問かつ、他の提案もしていただいたjun68ykt様にベストアンサーを付けさせていただきました。 とても勉強になりました。 ありがとうございました。
guest

0

js

1var objArray = [ 2 { grade: 'A', number: 2 }, 3 { grade: 'A', number: 3 }, 4 { grade: 'B', number: 1 }, 5 { grade: 'B', number: 2 }, 6 { grade: 'S', number: 1 }, 7 { grade: 'S', number: 2 } 8]; 9console.table(objArray); 10 11objArray.sort((a, b) => { 12 if(a.grade !== b.grade) { 13 if(a.grade === 'S') return -1; 14 return a.grade > b.grade? 1 : -1 15 } 16 if(a.number === b.number) return 0; 17 return a.number > b.number? 1 : -1 18}); 19console.table(objArray);

投稿2019/12/04 14:49

thyda.eiqau

総合スコア2982

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tkshp

2019/12/05 01:15

ご回答ありがとうございます。 ベストアンサー迷いましたが、私のwhileのイメージの疑問かつ、他の提案もしていただいたjun68ykt様にベストアンサーを付けさせていただきました。 とても勉強になりました。 ありがとうございました。
guest

0

ベストアンサー

こんにちは

ご質問にあるtkshp さんのコード

javascript

1while((var sValue = objArray.pop["grade"]) == "S"){ 2 objArray.unshift(sValue); 3}

について、

このようなイメージでコードを組むことは可能ですか?

とのことですが、一例としては以下かなと思います。

javascript

1const len = objArray.length; 2 3while (objArray[len-1].grade === 'S') { 4 objArray.unshift(objArray.pop()); 5}

または、 tkshp さんのコードにある、 「whileの条件式の中でpopして、末尾にあった要素を変数に格納する」というやり方を踏襲するならば、以下です。

javascript

1var sValue; 2while((sValue = objArray.pop()).grade === "S") { 3 objArray.unshift(sValue); 4} 5objArray.push(sValue);

上記のように、 while の条件の中で pop させると、 while から抜けた後に、最後にpopされた(gradeが 'S'ではない)要素を再度、objArray に追加しなければなりません。

追記

ご質問に

もしくはもっと簡潔な組み方はありますか?

とありましたので、(簡潔になっているかは分かりませんが、)別解を挙げます。
このご質問の前提である、入力される配列は

var objArray = [ { grade: 'A', number: 2 }, { grade: 'A', number: 3 }, { grade: 'B', number: 1 }, { grade: 'B', number: 2 }, { grade: 'S', number: 1 }, { grade: 'S', number: 2 } ];

というもので、この配列のインデクス4の要素{ grade: 'S', number: 1 }から末尾の要素{ grade: 'S', number: 2 }までの部分配列を、先頭に移動するにはどうしたらいいか?というのが与題です。 tkshp さんのご質問にあるコードは whileを使って1個ずつ移動するものですが、「(1個ずつではなく)部分配列ごと移動する」あるいは「ある配列を(共通部分を持たない)2つの部分配列に分割し、それらを入れ換える」という考え方もできます。以下はこの考え方によるコードです。

javascript

1const startIndexOfGradeS = objArray.findIndex(e => e.grade === 'S'); 2 3if (startIndexOfGradeS >= 0) { 4 objArray = [ 5 ...objArray.slice(startIndexOfGradeS), 6 ...objArray.slice(0, startIndexOfGradeS) 7 ]; 8}

追記2

ご質問の本題からは離れるかもしれませんが、以下、参考までに追記します。
もし、ご質問の前提である、入力される配列

var objArray = [ { grade: 'A', number: 2 }, { grade: 'A', number: 3 }, { grade: 'B', number: 1 }, { grade: 'B', number: 2 }, { grade: 'S', number: 1 }, { grade: 'S', number: 2 } ];

を得るためのソートを見直すことが可能で、ソートした結果として

[ { grade: 'S', number: 1 }, { grade: 'S', number: 2 }, { grade: 'A', number: 2 }, { grade: 'A', number: 3 }, { grade: 'B', number: 1 }, { grade: 'B', number: 2 } ]

が得られると望ましいということでしたら、sort に渡す比較関数を以下のようにすればよいかと思います。

javascript

1const compare = (a, b) => { 2 3 if (a.grade !== b.grade) { 4 if (a.grade === 'S') return -1; 5 if (b.grade === 'S') return 1; 6 return a.grade.localeCompare(b.grade); 7 } 8 9 return a.number - b.number; 10};

以下は、 要素をランダムに入れ換えたobjArrayを作り、それを上記の比較関数によってソートするサンプルです。

投稿2019/12/04 22:17

編集2019/12/05 00:46
jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tkshp

2019/12/05 01:14

ご回答ありがとうございます。 ベストアンサー迷いましたが、私のwhileのイメージの疑問かつ、他の提案もしていただいたjun68ykt様にベストアンサーを付けさせていただきました。 とても勉強になりました。 ありがとうございました。
jun68ykt

2019/12/05 01:16

どういたしまして。解決されたようで、よかったです????
tkshp

2019/12/09 02:04

すみません、解決後の質問で申し訳ないのですが、コードを何度かデバッグするうちに出力結果がおかしくなりまして、もし御存知でしたら教えていただけませんか? 詳細は追記しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問