- PR -

Java の Collections Framework はなぜ Set を sort できない?

投票結果総投票数:26
洗練されたフレームワーク 22 84.62%
くだらないできそこないのフレームワーク 4 15.38%
  • 投票は恣意的に行われます。統計的な調査と異なり、投票データの正確性や標本の代表性は保証されません。
  • 投票結果の正当性や公平性について、@ITは一切保証も関与もいたしません。
投稿者投稿内容
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2007-10-20 15:23
Java の Collections Framework
http://java.sun.com/javase/ja/6/docs/ja/technotes/guides/collections/overview.html
は、出てきた当時は便利だと感じましたが、今ではいろいろと不満があります。
とくに List と Set の使い分けがよく分かりません。
たとえばつぎの点です。

(1) Set を sort できないのはなぜか?(Collections#sort の引数は List であり Set ではない。)
(2) そのくせ TreeSet (SortedSet を implements したクラス)という sort を意識した Set がある。
(3) LinkedList は List なのにインデックスでアクセスしにくい。それをインデックスでアクセスできる(get(int) というメソッドを持つ)のは無理やりではないか?

私が思うには、
・要素に重複を許す・許さない。
・インデックスでアクセスできる・できない。
などといったことは、Collection (これは java.util.Collection) の持つちょっとした属性であり、それを違うサブタイプにする (List extends Collection と Set extends Collection に分ける)からフレームワークがややこしくなるのではないかと思います。

とくに大きな疑問としては、Java の Collections Framework は、(誰が作っても結局は同じになるような)洗練されたフレームワークとして参考にしたほうが良いのか、それとも、くだらないできそこないのフレームワークだと思って、使うケースによっては見切りをつけることがあっても良いのか、という見極めをどうしたらよいか?ということです。

どっちなんでしょう?

--
unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86}
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-10-20 16:31
引用:

unibonさんの書き込み (2007-10-20 15:23) より:
(1) Set を sort できないのはなぜか?(Collections#sort の引数は List であり Set ではない。)


単純にSetに対するソートは意味がないからです。
具象クラスのアルゴリズムを考えれば一目瞭然ですよ。

HashSetの要素を抽出してソートしてから再投入しても
アルゴリズム的に投入順は何ら意味を持ちません。

TreeSetにしても再投入時にはTreeSet自体に設定された
Comparatorの順で格納される事になります。

引用:

(2) そのくせ TreeSet (SortedSet を implements したクラス)という sort を意識した Set がある。


要素の一意性により重複を許さないコレクションがSetなので、
一意性の保証に利用するアルゴリズムの特性によっては
必然的にソートされているものもあると示しているだけです。

Listの特性を示したRandomAccessと同じようなものです。

引用:

(3) LinkedList は List なのにインデックスでアクセスしにくい。それをインデックスでアクセスできる(get(int) というメソッドを持つ)のは無理やりではないか?


そうですか?順アクセスを提供するためのIteratorもありますし、
現在ではRandomAccessでget(int)のコストの特性を把握できます。

むしろ、get(int)は一般的なコンテキストでは使うべきではなく、
RandomAccessであることを確認できた場合のチューニングの
目的にのみ使うべきだと思います。

引用:

私が思うには、
・要素に重複を許す・許さない。
・インデックスでアクセスできる・できない。
などといったことは、Collection (これは java.util.Collection) の持つちょっとした属性であり、それを違うサブタイプにする (List extends Collection と Set extends Collection に分ける)からフレームワークがややこしくなるのではないかと思います。


Setの活用方法が理解できないのならば、
Listのみを使っていればよいのではないでしょうか。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2007-10-20 17:12
TreeSetは結果として順序を持っているだけで、
どの場所に居るのかは意識されていません。
その結果としてSet#get(int)がありません。

抽象的な概念で考えるとSetはリストよりもMapに近いといえます。
Set<Entry<A,B>> = Map<A,B>#entrySet()
というように考えると納得できるかと思います。

ですので明示的にソートするのではなく、
列挙した際にどのような順で取得されるのかを
コンストラクタで明示的に指定するのが自然ではないでしょうか。

TreeSetではコンストラクタでソート方法を指定するようになっていますが、
iterator()を呼び出すときにソート方法を指定できると便利かもしれません。
でも今はIterableインターフェイスがあるので、
コンストラクタで指定するのが自然なのでしょう。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-10-20 18:04
引用:

かつのりさんの書き込み (2007-10-20 17:12) より:
TreeSetではコンストラクタでソート方法を指定するようになっていますが、
iterator()を呼び出すときにソート方法を指定できると便利かもしれません。


無理じゃないですか?二分木の構築に関わることなので
ツリー全体の再構築が必要になってしまいます。

それならListや配列に変換してsortした方がよいかと。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-10-20 19:11
Setがそもそも順序を持たないので、ソートすることがナンセンスですからねぇ。

TreeSet とか LinkedListあたりは実装の都合上、特定のメソッドが使いにくいと
いったところがありますが、その辺は確かに悩ましいところだとは思いますね。
どこかで共通項をくくりだしてインターフェースを定義せざるを得ないわけで
致し方ない部分だとは思います。
GENZO
大ベテラン
会議室デビュー日: 2003/11/26
投稿数: 111
お住まい・勤務地: 名古屋
投稿日時: 2007-10-20 21:02
確かに、私もSetやLinkedListってあまり使うことがありません。
使うとすると、Map#keySet()のときくらいでしょうか。

しかし、Collection Framework全体の設計や思想が複雑すぎたり使い勝手が悪いとは思いません。過去の経緯でArrayListとVectorのようにほとんど同じ意味のクラスは残っていますが、私は洗練されたフレームワークとして参考に出来ると思います。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2007-10-21 16:19
コメントありがとうございます。
拝見して思ったことを、まとまってはいませんが書きます。

引用:

あしゅさんの書き込み (2007-10-20 16:31) より:
引用:

(3) LinkedList は List なのにインデックスでアクセスしにくい。それをインデックスでアクセスできる(get(int) というメソッドを持つ)のは無理やりではないか?


そうですか?順アクセスを提供するためのIteratorもありますし、
現在ではRandomAccessでget(int)のコストの特性を把握できます。


RandomAccess があることを忘れていました。
これを読んで、Collection にはつぎの4とおりぐらいあると考えました(私の頭の中では)。
(a) Iterator はあるが順序がない。
(b) Iterator に順序がある。
(c) RandomAccess のリード(get(int))が低コストでできる。
(d) RandomAccess のライト(set(int, E))ができる。

引用:

かつのりさんの書き込み (2007-10-20 17:12) より:
TreeSetは結果として順序を持っているだけで、
どの場所に居るのかは意識されていません。
その結果としてSet#get(int)がありません。


これは(b)にあたると考えました。
Iterator が順序を保持して返すという役目を Set が持つことができる、ということを考える以上、どんなにコストが高くても良いとなれば Set であっても RandomAccess はリードについては原理的に可能なはずです。もちろん Set のサブタイプが Iterator を順序付きで返す場合だけですが。

引用:

nagiseさんの書き込み (2007-10-20 19:11) より:
Setがそもそも順序を持たないので、ソートすることがナンセンスですからねぇ。


実は、今回の最初の私の質問では、なんとなく頭の中に、たとえば、一例でしかありませんが、
「件名:Javaによるサーバ間ファイル同期について」
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=41738&forum=12
のようなアプリケーションでのファイル名の取り扱いを考えていました。
ファイル名の一覧だと、ファイル名は Set で持つことが多いかもしれませんが、たとえばこれを画面に表示する場合は、ソートはほぼ必須だと思います。こういうときに Set がソートできないのが使いづらいと考えます。
たとえば RDB も、集合を扱いますが、行の重複は許しますし、重複を許したくなければ unique 制約を付けたりします。これと同じことが Collections Framework ではできないことは、たまたまそういうフレームワークになっているだけであり、できるフレームワークがあっても良いと考えています。(もっとも行を主キーだけで考えた場合は重複なししかありえない、ということになりますが。)

引用:

GENZOさんの書き込み (2007-10-20 21:02) より:
確かに、私もSetやLinkedListってあまり使うことがありません。
使うとすると、Map#keySet()のときくらいでしょうか。


Set は Map に大きく依存していると思いますが、Map も含めて考えるとかなり大変なので、ちょっと Map についてはあまり調べていません。

--
unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86}
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2007-10-23 23:13
その後、ぼ〜っと Set や List のコードを眺めていて気づいたことがあります。
Set は Collection にメソッドを追加せず、ただたんにマーカーを付けただけであり、Collection とほとんど同等の扱いです。
一方、List は Collection からさらに10個のメソッドを追加しています。

また、やろうと思えば、
コード:
class MySortableSet<E> implements Set<E>, List<E> {
    ....
}


みたいなこともできます。

私は、今まで、Collection から並列に Set または List に分岐しているのかと思っていました。しかし、最初に、もし重複を許すならベースに Collection を選び、もし重複を許さないならベースに Set を選ぶ。そして、その後、List を implements する・しない、などは好きなようにやれば良い、という感じで捉えたほうが良いのかと思いました。

--
unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86}

スキルアップ/キャリアアップ(JOB@IT)