- - PR -
Java の Collections Framework はなぜ Set を sort できない?
投票結果総投票数:26 | |||
---|---|---|---|
洗練されたフレームワーク | 22票 | 84.62% | |
くだらないできそこないのフレームワーク | 4票 | 15.38% | |
|
投稿者 | 投稿内容 | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 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} | ||||||||||||||||||||
|
投稿日時: 2007-10-20 16:31
単純にSetに対するソートは意味がないからです。 具象クラスのアルゴリズムを考えれば一目瞭然ですよ。 HashSetの要素を抽出してソートしてから再投入しても アルゴリズム的に投入順は何ら意味を持ちません。 TreeSetにしても再投入時にはTreeSet自体に設定された Comparatorの順で格納される事になります。
要素の一意性により重複を許さないコレクションがSetなので、 一意性の保証に利用するアルゴリズムの特性によっては 必然的にソートされているものもあると示しているだけです。 Listの特性を示したRandomAccessと同じようなものです。
そうですか?順アクセスを提供するためのIteratorもありますし、 現在ではRandomAccessでget(int)のコストの特性を把握できます。 むしろ、get(int)は一般的なコンテキストでは使うべきではなく、 RandomAccessであることを確認できた場合のチューニングの 目的にのみ使うべきだと思います。
Setの活用方法が理解できないのならば、 Listのみを使っていればよいのではないでしょうか。 | ||||||||||||||||||||
|
投稿日時: 2007-10-20 17:12
TreeSetは結果として順序を持っているだけで、
どの場所に居るのかは意識されていません。 その結果としてSet#get(int)がありません。 抽象的な概念で考えるとSetはリストよりもMapに近いといえます。 Set<Entry<A,B>> = Map<A,B>#entrySet() というように考えると納得できるかと思います。 ですので明示的にソートするのではなく、 列挙した際にどのような順で取得されるのかを コンストラクタで明示的に指定するのが自然ではないでしょうか。 TreeSetではコンストラクタでソート方法を指定するようになっていますが、 iterator()を呼び出すときにソート方法を指定できると便利かもしれません。 でも今はIterableインターフェイスがあるので、 コンストラクタで指定するのが自然なのでしょう。 | ||||||||||||||||||||
|
投稿日時: 2007-10-20 18:04
無理じゃないですか?二分木の構築に関わることなので ツリー全体の再構築が必要になってしまいます。 それならListや配列に変換してsortした方がよいかと。 | ||||||||||||||||||||
|
投稿日時: 2007-10-20 19:11
Setがそもそも順序を持たないので、ソートすることがナンセンスですからねぇ。
TreeSet とか LinkedListあたりは実装の都合上、特定のメソッドが使いにくいと いったところがありますが、その辺は確かに悩ましいところだとは思いますね。 どこかで共通項をくくりだしてインターフェースを定義せざるを得ないわけで 致し方ない部分だとは思います。 | ||||||||||||||||||||
|
投稿日時: 2007-10-20 21:02
確かに、私もSetやLinkedListってあまり使うことがありません。
使うとすると、Map#keySet()のときくらいでしょうか。 しかし、Collection Framework全体の設計や思想が複雑すぎたり使い勝手が悪いとは思いません。過去の経緯でArrayListとVectorのようにほとんど同じ意味のクラスは残っていますが、私は洗練されたフレームワークとして参考に出来ると思います。 | ||||||||||||||||||||
|
投稿日時: 2007-10-21 16:19
コメントありがとうございます。
拝見して思ったことを、まとまってはいませんが書きます。
RandomAccess があることを忘れていました。 これを読んで、Collection にはつぎの4とおりぐらいあると考えました(私の頭の中では)。 (a) Iterator はあるが順序がない。 (b) Iterator に順序がある。 (c) RandomAccess のリード(get(int))が低コストでできる。 (d) RandomAccess のライト(set(int, E))ができる。
これは(b)にあたると考えました。 Iterator が順序を保持して返すという役目を Set が持つことができる、ということを考える以上、どんなにコストが高くても良いとなれば Set であっても RandomAccess はリードについては原理的に可能なはずです。もちろん Set のサブタイプが Iterator を順序付きで返す場合だけですが。
実は、今回の最初の私の質問では、なんとなく頭の中に、たとえば、一例でしかありませんが、 「件名:Javaによるサーバ間ファイル同期について」 http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=41738&forum=12 のようなアプリケーションでのファイル名の取り扱いを考えていました。 ファイル名の一覧だと、ファイル名は Set で持つことが多いかもしれませんが、たとえばこれを画面に表示する場合は、ソートはほぼ必須だと思います。こういうときに Set がソートできないのが使いづらいと考えます。 たとえば RDB も、集合を扱いますが、行の重複は許しますし、重複を許したくなければ unique 制約を付けたりします。これと同じことが Collections Framework ではできないことは、たまたまそういうフレームワークになっているだけであり、できるフレームワークがあっても良いと考えています。(もっとも行を主キーだけで考えた場合は重複なししかありえない、ということになりますが。)
Set は Map に大きく依存していると思いますが、Map も含めて考えるとかなり大変なので、ちょっと Map についてはあまり調べていません。 -- unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86} | ||||||||||||||||||||
|
投稿日時: 2007-10-23 23:13
その後、ぼ〜っと Set や List のコードを眺めていて気づいたことがあります。
Set は Collection にメソッドを追加せず、ただたんにマーカーを付けただけであり、Collection とほとんど同等の扱いです。 一方、List は Collection からさらに10個のメソッドを追加しています。 また、やろうと思えば、
みたいなこともできます。 私は、今まで、Collection から並列に Set または List に分岐しているのかと思っていました。しかし、最初に、もし重複を許すならベースに Collection を選び、もし重複を許さないならベースに Set を選ぶ。そして、その後、List を implements する・しない、などは好きなようにやれば良い、という感じで捉えたほうが良いのかと思いました。 -- unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86} |