はじめに
ソートと言えば、数値順・辞書順ですが、それ以外のソートについて調べてみました。
嵌った話
@jag_507 さんの*AtCoderでRuby学習10【第一回アルゴリズム実技検定 DoubleCamelCase Sort】を読んで、AtCoder 第一回アルゴリズム実技検定 F - DoubleCamelCase Sort*をやってみましたが、ソートがうまくいかないです。
a = ["FisH", "DoG", "CaT", "AA", "AaA", "AbC", "AC"]
a.sort
# => ["AA", "AC", "AaA", "AbC", "CaT", "DoG", "FisH"] # 実際の返り値
["AA", "AaA", "AbC", "AC", "CaT", "DoG", "FisH"] # 期待する返り値
この記事:*sortコマンド、基本と応用とワナ*の様な-f
オプションはないのか、ドラえもんGoogle先生助けてー。
大文字小文字を区別しないソート
Ruby に限らず多くのプログラミング言語の辞書順のソートはASCIIコード順での並び替え
になりますので、大文字と小文字では大文字が若くなります。
そこで、大文字小文字を区別しないソートが必要になります。
Ruby
a = ['a', 'b', 'c', 'd', 'e', 'A', 'B', 'C', 'D', 'E']
p a.sort
# => ["A", "B", "C", "D", "E", "a", "b", "c", "d", "e"]
p a
# => ["a", "b", "c", "d", "e", "A", "B", "C", "D", "E"]
p a.sort{|x, y| x.casecmp(y).nonzero? || x <=> y}
# => ["A", "a", "B", "b", "C", "c", "D", "d", "E", "e"]
p a.sort_by{ |s| [s.downcase, s] }
# => ["A", "a", "B", "b", "C", "c", "D", "d", "E", "e"]
casecomp が大文字小文字を区別しないメソッドになります。
追記
コメント欄よりsort_by
の解法をいただきました。
最優先s.downcase
と次優先s
の2つ条件でソートを行っています。
Python
a = ['a', 'b', 'c', 'd', 'e', 'A', 'B', 'C', 'D', 'E']
print(sorted(a))
# => ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e']
print(a)
# => ['a', 'b', 'c', 'd', 'e', 'A', 'B', 'C', 'D', 'E']
print(sorted(sorted(a), key=str.lower))
# => ['A', 'a', 'B', 'b', 'C', 'c', 'D', 'd', 'E', 'e']
ソート HOW TO に、大文字小文字を区別しない文字列比較の例が載っています。
Python のソートは安定なことが保証されていますので、2重にソートする方法が考えられます。
Java
List<String> a = Arrays.asList("a", "b", "c", "d", "e", "A", "B", "C", "D", "E");
a.sort(Comparator.naturalOrder());
System.out.println(a); // [A, B, C, D, E, a, b, c, d, e]
a.sort(String.CASE_INSENSITIVE_ORDER);
System.out.println(a); // [A, a, B, b, C, c, D, d, E, e]
Java の場合、CASE_INSENSITIVE_ORDER
が準備されています。
まとめ
- 大文字小文字を区別しないソート に詳しくなった
- Ruby に詳しくなった
- Python に詳しくなった
- Java に詳しくなった
- 自然順のソートまで手が回らなかった
参照したサイト
AtCoderでRuby学習10【第一回アルゴリズム実技検定 DoubleCamelCase Sort】
sortコマンド、基本と応用とワナ
casecomp
ソート HOW TO
[Java 8]コーディングテストで使えるアルファベット順、文字列長順のソート方法