質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

90.35%

  • JavaScript

    17461questions

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

JavaScriptで、プロパティ値をもとにオブジェクトをソートしたい

受付中

回答 4

投稿

  • 評価
  • クリップ 1
  • VIEW 275

tamogi

score 71

 前提・実現したいこと

あるサービスのAPIを叩くと、以下のようなレスポンスが返ってきます。

{
    "hoge": {
        "val": "val1",
        "index": 1
    },
    "piyo": {
        "val": "val3",
        "index": 3
    },
    "fuga": {
        "val": "val5",
        "index": 5
    },
    "foo": {
        "val": "val2",
        "index": 2
    },
    "bar": {
        "val": "val4",
        "index": 4
    }
}


毎回順番がランダムで取得されるので、indexプロパティの昇順でソートしたいです。

 試したこと

配列を用意し、indexの値をそのまま配列の添字に設定することで、ソート自体は出来ました。

ただし、2回ループしないといけないので書き方がダサいのと、keyの値が欲しくなった時に別途考慮しないといけないので、もう少しスマートな書き方があれば教えてください。

var apiResult = {...}; // 上記のオブジェクト

// 並び替え後の配列
var sortedArray = [];

// 並び替える
for (var key in apiResult) {
    // sortedArrayの添字にindexプロパティ値を設定
    sortedArray[apiResult[key]["index"]] = apiResult[key];
}

//確認
console.log(sortedArray);
// 1:{ val: "val1", index: 1 }
// 2:{ val: "val2", index: 2 }
// 3:{ val: "val3", index: 3 }
// 4:{ val: "val4", index: 4 }
// 5:{ val: "val5", index: 5 }

// 出力
for (var i = 1; i < sortedArray.length; i++) {
    console.log(sortedArray[i].val);
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+3

 {} のプロパティに順番はない

{} が持つプロパティに順番という概念はありません。
順番に意味があるなら、配列や  new Map のようなiterableなオブジェクトが必要です。

new Map(Object.entries(object).sort(function (a, b) {
  // ソート処理
}));

クロスブラウザはPolyfillで対応して下さい。

 Map.prototype.sort

一度、定義した new Map を再ソートする方法が標準で用意されていない為、再ソートには工夫が必要です。
https://gist.github.com/think49/daaf5ee0a4f12092862c81c54747bae5

Re: tamogi さん

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

こんにちは。

ソート後のデータ構造をどのように持つのか、用途によっていろいろ考えられそうですが、一例としてこの回答では、元のJSONから以下のような形のオブジェクト

{ key: "hoge", val:"val1", index:1 }


を要素とする配列を、

によって作成し、これを index の値の昇順になるように、

を使ってソートします。以下がそのコードです。

const jsonString = `{
    "hoge": {
        "val": "val1",
        "index": 1
    },
    "piyo": {
        "val": "val3",
        "index": 3
    },
    "fuga": {
        "val": "val5",
        "index": 5
    },
    "foo": {
        "val": "val2",
        "index": 2
    },
    "bar": {
        "val": "val4",
        "index": 4
    }
}`;

const dataObj = JSON.parse(jsonString);

const sortedAry = 
    Object.entries(dataObj)
           .map(([key, data]) => ({ key, ...data }))
           .sort((e1, e2) => e1.index - e2.index );

console.log(JSON.stringify(sortedAry, null, "\t"));


※上記のコードと同じものを、https://jsfiddle.net/jun68ykt/g956j2fn/39/ にも上げました。
  
これを実行すると、以下が出力されます。

[
    {
        "key": "hoge",
        "val": "val1",
        "index": 1
    },
    {
        "key": "foo",
        "val": "val2",
        "index": 2
    },
    {
        "key": "piyo",
        "val": "val3",
        "index": 3
    },
    {
        "key": "bar",
        "val": "val4",
        "index": 4
    },
    {
        "key": "fuga",
        "val": "val5",
        "index": 5
    }
]

以上参考になれば幸いです。


補足

プレーンオブジェクトのプロパティに順序がないことについては、以下の投稿で確認されるとよいかと思います。

上記、質問の回答の中で一番得票の多い回答 では、 ECMAScript Third Edition (pdf) からの引用で、以下が書かれています。

4.3.3 Object

An object is a member of the type Object. It is an unordered collection of properties each of which contains a primitive value, object, or function. A function stored in a property of an object is called a method.


補足2

think49さんがご回答で、og24715さんがコメントで、それぞれご提案されている Map を使ったコードを示します。for ... of を使ったときに、index の値の昇順に内容を列挙するようなMapオブジェクトを作成するには、以下のようにします。

const sortedEntriesByIndex = Object.entries(dataObj).sort(([key1, data1], [key2, data2]) => data1.index - data2.index);

const map = new Map(sortedEntriesByIndex);


上記のサンプル: https://jsfiddle.net/jun68ykt/jug198we/3/

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

こういうのは使う直前で用意するものです。
そしてJavaScriptにはメソッドチェーンで値を加工することが出来るので、
ObjectやArrayに紐づくメソッドをしっかり覚えれば数行で終わります。

例えば「indexプロパティの昇順でソート」されたものを画面表示するならばこう。

var apiResult = {
  hoge: {val: "val1", index: 1},
  piyo: {val: "val3", index: 3},
  fuga: {val: "val5", index: 5},
  foo: {val: "val2", index: 2},
  bar: {val: "val4", index: 4}
};

Object.values(apiResult)
  .sort((a, b) => a.index - b.index)
  .forEach(it => console.log(it.val));
// val1, val2, val3, val4, val5の順に出力

また、初期状態でkey: valueのオブジェクトになっていますが、
JS側からは使いにくいケースがありますので、
下記の様にオブジェクトの配列に変換して記憶させておくのも良いかもしれませんね。

この辺は一長一短なのでどちらで持つかは実装と好みみたいなもんです。
key: "hoge"で検索する頻度が高くなければ、
MySQLなんかのRDBは基本的に2次元の表形式なのでオブジェクトの配列として持っておくと分かりやすいかと思います。

var apiResult = {
  hoge: {val: "val1", index: 1},
  piyo: {val: "val3", index: 3},
  fuga: {val: "val5", index: 5},
  foo: {val: "val2", index: 2},
  bar: {val: "val4", index: 4}
};

var newResult = Object.keys(apiResult)
  .sort((a, b) => apiResult[a].index - apiResult[b].index)
  .map(key => ({key, ...apiResult[key]}));
console.log(newResult);
// [
//   {key: "hoge", val: "val1", index: 1},
//   {key: "foo", val: "val2", index: 2},
//   {key: "piyo", val: "val3", index: 3},
//   {key: "bar", val: "val4", index: 4},
//   {key: "fuga", val: "val5", index: 5}
// ]

// key: piyoを得たい
console.log(newResult.find(it => it.key === 'piyo'));
// {key: "piyo", val: "val3", index: 3}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/27 11:28

    結局1回は配列にしないといけないということですね。

    キャンセル

  • 2018/07/27 11:37

    > 1回は配列にしないといけない

    いえ、順番を持っているのは配列だけで、オブジェクトの要素に
    順番をつけることはできないということです

    キャンセル

  • 2018/07/27 11:58

    ちなみに、Map オブジェクトの key も順番持ってます。

    > The keys in Map are ordered while keys added to object are not.
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Objects_and_maps_compared

    キャンセル

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

  • ただいまの回答率 90.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • JavaScript

    17461questions

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