- PR -

TreeMapについて

投稿者投稿内容
未記入
会議室デビュー日: 2005/06/28
投稿数: 11
投稿日時: 2005-06-29 17:44
たびたびスミマセン。
所々間違って送っていました。
書き直さしていただきます。
public int compare(Object o1, Object o2) {
RecordSort r1 = (RecordSort)o1;
RecordSort r2 = (RecordSort)o2;
//int result = r1.busyoNo.compareTo(r2.busyoNo); 間違い
int result = r1.todou.compareTo(r2.todou);

if(result != 0){
return result;
}else{
//return r1.seikyusakiNo.compareTo(r2.seikyusakiNo);間違い
return r1.mise.compareTo(r2.mise);
}
}
Edosson
ぬし
会議室デビュー日: 2004/04/30
投稿数: 675
投稿日時: 2005-06-29 17:47
Recordインスタンスの値を入れ替えたとしても、
インスタンスそのものに変化はないからです。

以下のようにすれば、当初の期待通りになるでしょうか。
引用:

//ここからmainで処理が始まる
Map map = new TreeMap(new Record());
Record r1 = new Record();
r1.setTodou("大阪");
r1.setMise("002");
r1.setGetudo("3");
map.put(r1,"1000");

Record r2 = new Record();
r2.setTodou("東京");
r2.setMise("002");
r2.setGetudo("4");
map.put(r2,"2000");

System.out.println(map.get(r1));
System.out.println(map.get(r2));


さて、上記のような実装では、キーの保持や選択が面倒そうです。

Recordクラスに収支データのアクセサメソッドを実装して、

// 入れるとき
map.put(record.getTodou(),record);
// 取り出すとき
Record record = (Record)map.get("東京");

こんな感じにするのも一手かと。

[ メッセージ編集済み 編集者: Edosson 編集日時 2005-06-29 17:50 ]
Gio
ぬし
会議室デビュー日: 2003/11/28
投稿数: 350
お住まい・勤務地: 都内から横浜の間に少量発生中
投稿日時: 2005-06-29 18:04
引用:

未記入さんの書き込み (2005-06-29 17:36) より:

1000を出力してほしいにも関わらず、2000が表示されてしまいます。
これはどうしてなのでしょうか?



Edosson さんが書かれていますが、少し補足します。

コード:
r = new Record();
r.setTodou("東京");
r.setMise("002");
r.setGetudo("4");
map.put(r,"2000");

r.setTodou("大阪");
r.setMise("002");
r.setGetudo("3"); 



map.put(r,"2000") を実行した段階では、「東京+002+4」のキーに「2000」という値が対応付けられていますが、r を new Record() しないまま使いまわしたため、「2000」の値はそのままにキーだけが「大阪+002+3」に書き換えられてしまっています。
すなわち「大阪+002+3」というキーを持つエントリが二つ存在する状態になり、予期しない結果になったと考えられます。

# 以下蛇足:
# こういう掲示板では記事を書いている最中に他の方の投稿があり、内容が前後するのは
# ごく普通のことです。特に謝る必要はないと思いますよ
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2005-06-29 18:07
引用:

Gioさんの書き込み (2005-06-29 17:08) より:
コード:
TreeMap map; 
...
Record key = new Record();
Value val = new Value(); // key に関連付ける値

key.setAge(/* 年齢 */);
...
map.put(key, val);



取得は
コード:
Record anotherKey = new Record();
anotherKey.setAge(/* 年齢 */);
...
Value v = (Value) map.get(anotherKey);


のようになります。




この方法だと、equalsメソッドを実装しないと取得できないと思います。
(hashCodeメソッドの実装も必要だったっけ・・・?)
Javaのオブジェクトは同一性を調べる為にequalsメソッドが存在します。
このメソッドをオーバーライドして、ソート方法の実装同様、
同一性確認の方法を実装する必要があります。
実装しない限り、比較は==で行われます。

コード:
public boolean equals(Object obj){
    Record r = (Record) obj;
    return r.age == age && r.name.equals(name);
}


みたいな実装が必要になります。
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2005-06-29 18:28
要件から見ると、がんばってMap実装を使用するより、Compositeパターン
によるツリー構造を作っちゃった方が簡単そうな気がしましたが。

下記コードの出力は

2000
40000
50000
null
null

になります。

コード:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;

public class Tree {
	
	public static class Node{

		private ArrayList children = new ArrayList();
		private Object value;
		
		private Node(Object value){
			if(value == null)value = "null";
			this.value = value;
		}
		
		private void add(LinkedList path,Object value){
			if(path.size() == 0){
				children.add(new Node(value));
				return;
			}
			Node token = new Node(path.removeFirst());
			int index = children.indexOf(token);
			if(index >= 0)
				token = (Node)children.get(index);
			else
				children.add(token);
			token.add(path,value);
		}
		
		private Object search(LinkedList path){
			if(path.size() == 0){
				return ((Node)children.get(0)).getValue();
			}
			Node token = new Node(path.removeFirst());
			int index = children.indexOf(token);
			if(index >= 0)
				return ((Node)children.get(index)).search(path);
			else
				return null;
		}

		public boolean equals(Object dst){
			if(dst == null || dst.getClass() != getClass())
				return false;
			return ((Node)dst).value.equals(value);
		}
		
		public Object getValue(){return value;}
	
	}

	private Node root = new Node(null);
	
	public void add(Object[] path,Object value){
		LinkedList l = new LinkedList(Arrays.asList(path));
		root.add(l,value);
		
	}

	public Object search(Object[] path){
		LinkedList l = new LinkedList(Arrays.asList(path));
		return root.search(l);
	}


	public static void main(String args[]){
		
		Tree tree = new Tree();
		tree.add(new Object[]{"東京","002","3"},"2000");
		tree.add(new Object[]{"東京","003","3"},"1000");
		tree.add(new Object[]{"東京","003","4"},"500");
		tree.add(new Object[]{"大阪","004","1"},"50000");
		tree.add(new Object[]{"大阪","003","3"},"40000");
		
		System.out.println(tree.search(new Object[]{"東京","002","3"}));
		System.out.println(tree.search(new Object[]{"大阪","003","3"}));
		System.out.println(tree.search(new Object[]{"大阪","004","1"}));
		System.out.println(tree.search(new Object[]{"東京","002","4"}));
		System.out.println(tree.search(new Object[]{"大阪","003","3","うそ"}));
	}


}



何が起きているかを把握したいなら、デバッガで追ってみてください。
Gio
ぬし
会議室デビュー日: 2003/11/28
投稿数: 350
お住まい・勤務地: 都内から横浜の間に少量発生中
投稿日時: 2005-06-29 18:32
引用:

かつのりさんの書き込み (2005-06-29 18:07) より:

この方法だと、equalsメソッドを実装しないと取得できないと思います。
(hashCodeメソッドの実装も必要だったっけ・・・?)



これについては私も気になり TreeMap クラスの API を調べましたが、以下のような記述があります。
(以下 J2SE 1.4.2 API の TreeMap クラスの説明から第 3 パラグラフを引用; 斜体部は私が入れたものです)
引用:

Note that the ordering maintained by a sorted map (whether or not an explicit comparator is provided) must be consistent with equals if this sorted map is to correctly implement the Map interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Map interface is defined in terms of the equals operation, but a map performs all key comparisons using its compareTo (or compare) method, so two keys that are deemed equal by this method are, from the standpoint of the sorted map, equal. The behavior of a sorted map is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Map interface.



この説明により、ハッシュ系コレクションとは異なり TreeMap では Object#equals(Object) のオーバーライドは不要と考えました。
いかがでしょうか。
未記入
会議室デビュー日: 2005/06/28
投稿数: 11
投稿日時: 2005-06-29 18:41
スミマセン。Gioさんに質問なのですが、
一応、putの前にnew Record() をしてみたのですが、
値が同じように出力される結果になってしまいました。
他に原因は何があるでしょうか?
----------------------------------------
while (db.moveNext()){
r = new RecordKey();//newを入れてみました。
//データベースからデータを取得(一意なので被る事はない)
r.setTodou(rec.getString("TODOU"));
r.setMise(rec.getString("MISE"));
r.setGetudo(rec.getString("GETUDO"));

map.put(r,value);
}

r = new RecordKey();
r.setTodou(todou);
r.setMise(mise);
r.setGetudo(yearMonth);//←強引に値を入れても反応無し
System.out.println(map.get(r));//同じ値しか出てこない
----------------------------------------
todouとmiseでは反応しているみたいなのですが、
yearMonthを強引に直書きをしても、
特に反応が無い状態です。
yearMonth="200501"
yearMonth="33"
などを強制的に入れても、
同じ値(2000)しか出力されない状態です。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2005-06-29 19:08
>Gioさん

なるほど。
TreeMapのソースを追っかけてみましたが、
中のEntryクラスはequalsで比較していますね。
これで実装はどうなるんだろう・・・

あとで試してみよう・・・

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