///

連想配列(オブジェクトの値)の並び替え

wrote :

たとえば下記のような配列(sample)で、配列に格納したオブジェクトの指定したキー(b)の値で並び替えたいとき。また配列(sample2)で、配列に格納した配列の指定した引数(2番目)の値で並び替えたいとき。

sample = [
  {
    a: 300,
    b: 220,
    c: "blueberry"
  }, {
    a: 800,
    b: 100,
    c: "apple"
  }, {
    a: 1200,
    b: 120,
    c: "orange"
  }
];

sample2 = [
  [300, 220, 'blueberry'],
  [800, 100, 'apple'],
  [1200, 120, 'orange']
];

期待する結果は次のとおり(sampleは各オブジェクトをbの値をキーにして昇順に。sample2は各配列を第2引数をキーにして昇順に)。

sample = [
  {
    a: 800,
    b: 100,
    c: "apple"
  }, {
    a: 1200,
    b: 120,
    c: "orange"
  }, {
    a: 300,
    b: 220,
    c: "blueberry"
  }
];

sample2 = [
  [800, 100, 'apple'],
  [1200, 120, 'orange'],
  [300, 220, 'blueberry']
];

実装イメージ

並び替え用の関数をあらかじめ読み込んで、その関数に必要なパラメータを渡して実行する。以上。

連想配列並び替え用の関数
function arySort(ary, ky, st) {
  var ary_ky = ('string' == typeof ky || 'number' == typeof ky)? new Array(ky): ky,
  ary_ky_num = ary_ky.length,
  ary_st = [],
  key = null,
  srt = null;

  // 並び替え(降順かどうか)
  if ('boolean' == typeof st) {
    ary_st.push(st);
  } else if (st) {
    ary_st = st;
  }
  
  ary.sort(function(a, b) {
    function ary_chk(i) {
      key = ary_ky[i];
      srt = (ary_st[i])? -1: 1;

      if (a[key] < b[key]) {
        return -1 * srt;
      } else if (a[key] > b[key]) {
        return 1 * srt;
      } else {
        if (i < ary_ky_num) {
          return ary_chk(i+1);
        } else {
          return 0;
        }
      }
    }
    return ary_chk(0);
  });
};
続いて、関数を実行すれば期待どおりの結果が得られる。
// 第1引数(必須) 並び替えをしたい配列
// 第2引数(必須) どの値で並び替えをしたいのか、そのキー
arySort(sample, 'b');
arySort(sample2, 1);

ちなみに、第3引数は降順にするかどうか(デフォルト false: 昇順)。

arySort(sample, 'b', true);
arySort(sample2, 1, true);

結果は次のとおり(sampleは各オブジェクトをbの値をキーにして昇順に。sample2は各配列を第2引数をキーにして昇順に)。

sample = [
  {
    a: 300,
    b: 220,
    c: "blueberry"
  }, {
    a: 1200,
    b: 120,
    c: "orange"
  }, {
    a: 800,
    b: 100,
    c: "apple"
  }
];

sample2 = [
  [300, 220, 'blueberry'],
  [1200, 120, 'orange'],
  [800, 100, 'apple']
];

もうちょっと複雑なサンプル

下記のように、第2引数と第3引数を配列にして記述することもできます。
第2引数の配列の中身は、並び替えをしたい配列の番号(number)もしくはオブジェクトのキー(string)。第3引数の配列の中身は、降順にしたい場合は(boolean)をセット。下記サンプルです。

// 昇順の場合
arySort(sample, ['b']);
arySort(sample2, [1]);

// 降順の場合
arySort(sample, ['b'], [true]);
arySort(sample2, [1], [true]);

こうすることで、第一優先、第二優先、・・・第n優先での並び替えができるようしています。

最終サンプル

サンプル配列
sample3 = [
  {txt: 'あいうえお', a: 1, b: 33},
  {txt: 'かきくけこ', a: 3, b: 11},
  {txt: 'かきくけこ', a: 6, b: 11},
  {txt: 'さしすせそ', a: 9, b: 11},
  {txt: 'たちつてと', a: 2, b: 33},
  {txt: 'なにぬねの', a: 4, b: 11},
  {txt: 'はひふへほ', a: 8, b: 33},
  {txt: 'まみむめも', a: 6, b: 77},
  {txt: 'まみむめも', a: 7, b: 77},
  {txt: 'まみむめも', a: 6, b: 11},
  {txt: 'まみむめも', a: 9, b: 77},
  {txt: 'まみむめも', a: 1, b: 77},
  {txt: 'やいゆえよ', a: 5, b: 11},
  {txt: 'らりるれろ', a: 1, b: 77},
  {txt: 'わわわをん', a: 3, b: 77}
]
実行例
// 第1優先 'b' 降順 
// 第2優先 'txt' 昇順
// 第3優先 'a' 降順
arySort(sample3, ['b', 'txt', 'a'], [true, false, true]);
結果
sample3 = [
  {txt: 'まみむめも', a: 9, b: 77},
  {txt: 'まみむめも', a: 7, b: 77},
  {txt: 'まみむめも', a: 6, b: 77},
  {txt: 'まみむめも', a: 1, b: 77},
  {txt: 'らりるれろ', a: 1, b: 77},
  {txt: 'わわわをん', a: 3, b: 77},
  {txt: 'あいうえお', a: 1, b: 33},
  {txt: 'たちつてと', a: 2, b: 33},
  {txt: 'はひふへほ', a: 8, b: 33},
  {txt: 'かきくけこ', a: 6, b: 11},
  {txt: 'かきくけこ', a: 3, b: 11},
  {txt: 'さしすせそ', a: 9, b: 11},
  {txt: 'なにぬねの', a: 4, b: 11},
  {txt: 'まみむめも', a: 6, b: 11},
  {txt: 'やいゆえよ', a: 5, b: 11}
]

さいごに

予期せぬパラメータが渡った時の処理はしておりません(自分で使う分にはそこまでのケアが必要でないため)。でもあとで予期せぬパラメータが渡ったとき対応しておくかも。

これまでは、配列の並び替えが必要になるたびに優先する数だけコピペして関数を作ってましたが、これでようやくすっきりできました(一年前はちんぷんかんぷんでしたが、今回はだいぶ理解しながらチューニングできました。来年はもっと理解できてるといいな、なんて思います)。

川上 武範(かわかみ たけのり)
1975年生。シンプルシンプルデザイン代表兼Webクリエイター。たびのとWebサイト運営責任者。

企画からサイト設計、正しいマークアップを意識したWebサイト制作やユーザー視点の情報設計を得意としている。

シンプルシンプルデザイン
たびのと
twitter : たけたけ@OnlyTwo

メディア掲載
2016年10月25日 レバテックフリーランスの記事「自作Webサービス記事紹介まとめ」でサイト内の記事「Webサービス「たびのとTOKYO」を作ってみました」を紹介していただきました。