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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

14271閲覧

Java Comparator.naturalOrder()の自然な順序とは?

BitCoin

総合スコア53

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

1クリップ

投稿2017/08/25 23:08

編集2017/08/25 23:09

###ストリームAPIについて

ソースコード1について

maxメソッドと引数についてですが、Comparator.naturalOrder()は自然な順序で
比較するとリファレンスにありました。
該当のソースコード1で試したところ「いあ」という文字列が返りましたが、この自然な順序というのはどいうことでしょう?
なぜローマ字より先に全角の日本語がかえるのでしょうか?
辞書順ソート?

ソースコード2について

どうやらmaxメソッドの引数に(d1,d2) -> d1.length() - d2.length()とすると作成したストリームから最大長の文字列を返すらしいのですが、なぜ引数を二つとり、長さを比較すると最大の長さの文字列が返るのでしょうか?

よろしくお願いします。
###該当のソースコード1

java

1List<String> data = Arrays.asList("aaa","bb","cccc","d","g","いあ","あい"); 2 3Optional<String> result1 = data.stream().max(Comparator.naturalOrder()); 4result1.ifPresent(System.out::println);

###該当のソースコード2

java

1Optional<String> result2 =data.stream().max((d1,d2) -> d1.length() - d2.length()); 2result2.ifPresent(System.out::println);

###返り値

java

1ソース1 いあ 2ソース2 cccc 3 4

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

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

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

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

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

guest

回答2

0

ベストアンサー

###オブジェクトの順序付け
あるクラスのインスタンス同士に順序を付ける方法は2通りあります。
0. そのクラスにComparableインタフェースを実装する
0. Comparatorインタフェースのオブジェクトを作成する

1.の方法で順序を付けることを自然順序付けと呼びます。
###目的
リストなど、要素の集合をソートするというのはよくある要求です。「ソート アルゴリズム」などで検索すれば様々な記事がヒットするはずです。そこで解説しているのはもっぱら数値のソートですが、どのアルゴリズムを見ても、基本的にやっていることは「2つの要素の大小を比較して、結果により入れ替える」ことで、異なるのは比較する要素の取り出し方や入れ替えのルール程度です。
そこで、一般のオブジェクト2つに対して、その2つの大小を比較することができれば、数値のソートと同じようにソートができることになります。この大小を決定するのがComparableやComparatorなのです。
###比較のメソッド
Comparableインタフェースは引数を1つとるcompareToメソッドを持ち、次のように使います。

java

1// Stringは辞書順に並ぶよう順序付けするようComparable#compareToメソッドを実装している 2String a = "a"; 3String b = "b"; 4// 一方のインスタンスのメソッドの引数に、そのインスタンスと比較するインスタンスを渡す 5int i = a.compareTo(b);

Comparatorインタフェースは引数を2つとるcompareメソッドを持ち、次のように使います。

java

1// 文字列の長さの大小で比較するComparator(後ほど解説) 2Comparator<String> comparator = (x, y) -> x.length() - y.length(); 3String a = "a"; 4String b = "bbb"; 5// Comparatorオブジェクトのメソッドの引数に比較する2つのインスタンスを渡す 6int i = comparator.compare(a, b);

これらのメソッドはint型の値を返します。これらのメソッドは、どちらがより大きいかを、返り値の正負で判断できるように設計する必要があります。
今便宜上、xというインスタンスがyより小さい、つまり昇順に並べた際xがyより先に並ぶということをx < yと表現することにすると、

  • Comparableの場合

x < y と x.compareTo(y) < 0 が同値

  • Comparatorの場合

Comparatorオブジェクトをcとしたとき、
x < y と c.compare(x, y) < 0 が同値

になるようにします。
###本題 - 回答
まずいずれのソースコードにも共通することですが、
Stream#maxメソッドは引数にComparatorオブジェクトを渡し、そのComparatorに従って順序付けして、その最大の要素、つまり昇順に並べて最後に来る要素を返すものです。

ソースコード1において、自然順序付けはすでに書いた通り、そのクラスのComparableインタフェースで定義された順序付けをすることを意味します。したがって、次の2つのComparatorは同じ順序付けをします。

java

1Comparator<String> c1 = Comparator.naturalOrder(); 2Comparator<String> c2 = (s1, s2) -> s1.compareTo(s2);

ソースコード2においては、Comparator#compareメソッドの実装をラムダ式で行っています。
これで文字列の短い順に並ぶ理由についてですが、少し数学の話をします。
任意の実数a,bに対して、a < b と a - b < 0 は同値です。
今このmaxメソッドに渡しているComparatorは、2つの文字列のlength()、つまり長さの差を取ることで、長さの大小を比較していることになります。この符号が正か負かで、どちらが長いかが決定できます。
そして負であるとき、つまりd1のほうが短いとき、メソッドの設計の話からd1が昇順で先に並ぶことになります。
maxメソッド内ではこれを自動でやってくれるのでd1とかd2に当たるものが何か外部からは見えませんが、「短いものから先に並ぶ」という要件にはなっています。
※今回の場合は「文字列の長さ」のため、両方0以上の値であるから引き算で比較できたが、一般のint値同士を引き算で比較するとオーバーフローする恐れがあるので注意が必要
また次のように書くことも可能

java

1Optional<String> result2 = data.stream().max(Comparator.comparingInt(String::length));

こうすることで、「文字列の長さで比較」ということを明示的にできる

投稿2017/08/26 00:45

編集2017/08/26 14:47
swordone

総合スコア20649

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

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

BitCoin

2017/08/26 07:12

回答ありがとうございます! 思ったより深いところまで考えなければならないのですね。頑張って理解します!
guest

0

ソースコードの1については、

なぜローマ字より先に全角の日本語がかえるのでしょうか?

.maxを取っていますので、返ってくる結果は「辞書順ソート」での最後のものになります。

ソースコード2については、「比較関数が正ならd1を後に、負ならd2を後に」というようにソートしていきますので、長さの順に並びます(これは「習うより慣れろ」の側面も強いです)。

投稿2017/08/26 00:11

maisumakun

総合スコア145121

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

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

BitCoin

2017/08/26 00:38

回答ありがとうございます。 少しわからなかったことがあるのですが ソース2についてですが、「比較関数が正ならd1を後に、負ならd2を後に」という意味ですが (d1,d2) -> d1.length() - d2.length()をmax()にわたすと はd1とd2にdata.stream()のなかの"aaa","bb","cccc","d","g","いあ","あい"を渡しすべての長さを比較し、その差が一番小さかったd1を返すという認識であっているでしょうか? いずれにせよmax()の中でどのような操作が行われているのかわからず・・・・ こういう場合は理解することはお手上げなのでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問