1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Rubyで配列をちょっとした条件でソートする

Posted at

ある配列を独自の条件でソートするときもsort_byを使うとたいへん便利なのですが、書き方を失敗したときのエラーがわかりにくい場合があったので記事を書いてみます(5年くらい前もあれ、となっていたので)。

> (1..10).to_a.reverse
=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

たとえばこんな配列があります。これを昇順にソートするには単純にsortを使えばよい。

> (1..10).to_a.reverse.sort
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

これを偶数を先に並べるにはどうしましょう。
sort_byをつかうと簡単です。

> (1..10).to_a.reverse.sort_by{|i| i % 2}
=> [10, 8, 6, 4, 2, 9, 7, 5, 3, 1]

偶数が先だけれど、昇順にしたいときは、sort_byのなかを配列にするとできます。

> (1..10).to_a.reverse.sort_by{|i| [i % 2, i]}
=> [2, 4, 6, 8, 10, 1, 3, 5, 7, 9]

数字か文字列かで違うこともあまりないんですが、文字列で特定の文字を含む場合に先に並べたいときはどうでしょうか。同じようにやってみると・・・

>  ["さばねこ","いぬ","しばいぬ","ねこ","とらねこ","あきたいぬ" ]
.sort_by{|animal| animal.include?("いぬ")} 
ArgumentError: comparison of Array with Array failed

エラーが出ました。
配列と配列を比べていると失敗しています。ちょっとやっていることとわかりにくく、うまく説明できませんが、TrueやFalseといったBoolean同士を比較できないから、ではないかと思います(どなたかいい説明あれば教えてください・・・)

原因はさておき、どう解決するか。三項間演算子で数字にするのが簡単です。

> ["さばねこ","いぬ","しばいぬ","ねこ","とらねこ","あきたいぬ" ]
.sort_by{|animal| [animal.include?("いぬ") ? 0 : 1]}
=> ["いぬ", "しばいぬ", "あきたいぬ", "さばねこ", "ねこ", "とらねこ"]

いぬが先でそのなかで辞書順にするにはこうします

> ["さばねこ","いぬ","しばいぬ","ねこ","とらねこ","あきたいぬ" ]
.sort_by{|animal| [animal.include?("いぬ") ? 0 : 1, animal]}
=> ["あきたいぬ", "いぬ", "しばいぬ", "さばねこ", "とらねこ", "ねこ"]

はい。
簡単でした。多次元配列やHashの配列であっても同じような考え方でsort_byを使うと簡単です。配列に列挙していくのでなにを優先させるかもわかりやすいですね。

参考)
sort_by のドキュメントはこちら。
https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/sort_by.html

1
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?