- PR -

ハッシュテーブルについて

1
投稿者投稿内容
しん
常連さん
会議室デビュー日: 2004/04/04
投稿数: 48
投稿日時: 2004-04-04 02:59
自作のhashtblクラス内のhash()メッソドに渡される引数に応じて戻り知が異なることを
期待してコンパイルし実行してみたのですが結果は
[{NAIYO=どらえもん, NO=1}, {NAIYO=どらえもん, NO=1}, {NAIYO=どらえもん, NO=1}
,{NAIYO=どらえもん, NO=1}] という結果でした。
期待していた結果としては
[{NAIYO=どらえもん, NO=1}, {NAIYO=doraemon, NO=2}, {NAIYO=星陵高校, NO=3}
,{NAIYO=ガリクソン, NO=6}]
だったのですがなぜこのような結果になるのでしょうか?
hashtblクラス内の
String key = (String)e.nextElement();
がうまく機能していないのでしょうか?

(hash.java)
import java.util.*;
public class hash {

public static void main(String args[]) {
hashtbl has = new hashtbl();
Vector vec;
vec = has.hash(2);
}



(hashtbl.java)
import java.util.*;
public class hashtbl {
public Vector hash(int k) {
Vector vec1 = new Vector();
Vector vec2 = new Vector();
Hashtable has1 = new Hashtable();
Hashtable has2 = new Hashtable();
has1.put("1","どらえもん");
has1.put("2","doraemonn");
has1.put("3","星陵高校");
has1.put("4","ゴンザレス");
has1.put("5","カレー");
has1.put("6","ガリクソン");
Enumeration e = has1.keys();

while(e.hasMoreElements()) {
String key = (String)e.nextElement();
String value = (String)has1.get(key);
has2.put("NO",key);
has2.put("NAIYO",value);
if(key.equals("4") || key.equals("5")){
vec1.addElement(has2);
}else{
vec2.addElement(has2);
}
}
if(k==1){
return vec1;
}else{
return vec2;
}

}
}
でゅうく
大ベテラン
会議室デビュー日: 2003/11/30
投稿数: 129
投稿日時: 2004-04-04 10:53
何をやりたいのか分からないので、はずしているかもしれませんが。
以下のようにしたらどうでしょうか?
コード:
	while (e.hasMoreElements()) {
		String key = (String) e.nextElement();
		String value = (String) has1.get(key);
		Hashtable has2 = new Hashtable();  // ※ここでインスタンス化
		has2.put("NO", key);
		has2.put("NAIYO", value);
		if (key.equals("4") || key.equals("5")) {
			vec1.addElement(has2);
		} else {
			vec2.addElement(has2);
		}
	}


e.nextElement() では 6, 5, 4 ... 1 の順に key が渡されているのでしょう。
最終的に返す Vector にはいつも同じ Hashtable インスタンスを追加しているので、結果として最後に返ったどらえもんで全ての要素が置き換わっってしまいます。
毎回 Hashtable をインスタンス化してやれば、別々に格納されると思います。
しん
常連さん
会議室デビュー日: 2004/04/04
投稿数: 48
投稿日時: 2004-04-04 12:16
引用:

ご返答ありがとうございます。
早速ためしてみたところうまくいきました。
DBに存在するデータによってメッソドhash()に渡す引数を変え、それに応じ
返ってきた結果をプルダウンにしようと思っていたので試しにこのようなサンプルを作って
みたわけです。本当にありがとうございました。

しん
常連さん
会議室デビュー日: 2004/04/04
投稿数: 48
投稿日時: 2004-04-11 14:47
引用:

でゅうくさんの書き込み (2004-04-04 10:53) より:
何をやりたいのか分からないので、はずしているかもしれませんが。
以下のようにしたらどうでしょうか?
コード:
	while (e.hasMoreElements()) {
		String key = (String) e.nextElement();
		String value = (String) has1.get(key);
		Hashtable has2 = new Hashtable();  // ※ここでインスタンス化
		has2.put("NO", key);
		has2.put("NAIYO", value);
		if (key.equals("4") || key.equals("5")) {
			vec1.addElement(has2);
		} else {
			vec2.addElement(has2);
		}
	}


e.nextElement() では 6, 5, 4 ... 1 の順に key が渡されているのでしょう。
最終的に返す Vector にはいつも同じ Hashtable インスタンスを追加しているので、結果として最後に返ったどらえもんで全ての要素が置き換わっってしまいます。
毎回 Hashtable をインスタンス化してやれば、別々に格納されると思います。



先週、私の質問に対して上記のような御回答を頂きました。御回答の通り試してみたところ
私の期待通りにうまくいきました。
前回とほぼ同様、ハッシューテーブルオブジェクトに格納したkeyとvalueを
表示するサンプルを作成し実行した結果、疑問が浮上しましたので質問させていただきます。

コード:
import java.util.*;
public class hash1 {

          public static void main(String args[]) {
                     Vector vec = new Vector();
                     Hashtable has1 = new Hashtable();
                     has1.put("1","どらえもん");
                     has1.put("2","doraemonn");
                     has1.put("3","星陵高校");
                     has1.put("4","ゴンザレス");
                     has1.put("5","カレー");
                     has1.put("6","ガリクソン");
                     Enumeration e = has1.keys();

                      Hashtable has2 = new Hashtable(); //ここでインスタンス化
                   while(e.hasMoreElements()) {
                              String key = (String)e.nextElement();
                              String value = (String)has1.get(key);
                              has2.put(key,value);
                              
                   }

                  System.out.println(has2);
                  
          }



}


この結果は、{6=ガリクソン, 5=カレー, 4=ゴンザレス, 3=星陵高校, 2=doraemonn,
1=どらえもん}でした。
前回の質問ではwhileループの外でインスタンス化したためHashtableオブジェクトの中身が
ループの最終結果に置き換るということでしたがこのことを踏まえると上記の結果は
不思議に思います。、私の予想では{1=どらえもん}という結果しか帰ってこないと思って
いました。よろしくお願いいたします。

unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2004-04-11 17:17
unibon です。こんにちわ。

引用:

かんたろうさんの書き込み (2004-04-11 14:47) より:
前回の質問ではwhileループの外でインスタンス化したためHashtableオブジェクトの中身が
ループの最終結果に置き換るということでしたがこのことを踏まえると上記の結果は
不思議に思います。、私の予想では{1=どらえもん}という結果しか帰ってこないと思って
いました。よろしくお願いいたします。


なにが分からないのかは分かったつもりです。

インスタンス化とループの内・外というのは直接の関係はないです。たまたまそうだからです。
a.add(b) や a.put(b, c) において、
put や add の引数となる b や c と、
put や add の操作の対象となる a との違いです。
b や c は add や put が終わっても、
a の管理の外で依然として内容を変化させることができます。
#うまく説明できません。

まだ先は長いので、できればデバッガを使われて1行ずつステップ実行されて変数をウォッチされるほうが手っ取り早いと思います。ただ、Hashtable はデバッガでも中の値が見づらいので、最初はもっと手軽な配列等で試されたほうが良いかもしれません。
もし、デバッガを使われないとすれば、随所に System.out.println を埋め込んで、行の前後での値の変化を見られたほうが良いでしょう。
でゅうく
大ベテラン
会議室デビュー日: 2003/11/30
投稿数: 129
投稿日時: 2004-04-11 21:26
ループの外で has2 をインスタンス化するということは、このプログラム内で has1 以外の Hashtable オブジェクトは一つしか無いという事です。
かんたろうさんのコードでは Hashtable のインスタンスである has2 に対し、キーの値を固定して(NO と NAIYO)追加していますよね。
has2 に put する度に内容が追加される訳ではなく、置き換えられている訳です。
以下はループ内での has2 の状態です。
コード:
1 回目 NO    : 6
     NAIYO : ガリクソン

2 回目 NO    : 5
     NAIYO : カレー

       ↓(省略)

6 回目 NO    : 1
     NAIYO : どらえもん


上記のように、どのタイミングでも has2 が持つ要素は NO と NAIYO に対応した二つしかありません。
has2 を 格納する Vector のインスタンスである vec2 は、全ての要素がただ一つの has2 への参照なので、最後に置き換えられた「どらえもん」がずらりと並ぶことになるのです。

対して、ループの内で has2 をインスタンス化する場合は、今回の例では has2 に対して 6 つの インスタンスが生成されます。
別々に生成して vec2 に追加する訳ですから、上記のような置き換えが発生しないので個々の値を持ち続けられるのです。

かんたろうさんが改めて質問したコードでは Hashtable に追加する際に、キーの値を毎回変えて追加していますので、全て別々の要素として(置き換えられる事無く)存在できるのです。
でゅうく
大ベテラン
会議室デビュー日: 2003/11/30
投稿数: 129
投稿日時: 2004-04-11 22:27
余計なお世話かもしれませんが、has2 としての Hashtable の使い方がいまいちズレているように感じます。
最終的に欲しい内容がプルダウンにしたい内容の一覧であるならば、値を保持するクラスを作って、それを Vector に追加するのがいいのではないでしょうか?

例えば、こんなクラスを作って
コード:
public class ValueObject {
	public String no;    // 通常は private にして 対応するアクセッサを作成する
	public String naiyo; // 同上
	public ValueObject(String no, String naiyo) {
		this.no = no;
		this.naiyo = naiyo;
	}
	public String toString() {
		return "NO=" + no + " NAIYO=" + naiyo;
	}
}


こうしてみるとか
コード:
		Vector vec1 = new Vector();
		Vector vec2 = new Vector();
		Hashtable has1 = new Hashtable();
//		Hashtable has2 = new Hashtable();   不要になります
		has1.put("1", "どらえもん");
		has1.put("2", "doraemonn");
		has1.put("3", "星陵高校");
		has1.put("4", "ゴンザレス");
		has1.put("5", "カレー");
		has1.put("6", "ガリクソン");
		Enumeration e = has1.keys();

		while (e.hasMoreElements()) {
			String key = (String) e.nextElement();
			String value = (String) has1.get(key);
			// さっきのクラスをここで使う
			ValueObject o = new ValueObject(key, value);
			if (key.equals("4") || key.equals("5")) {
				vec1.addElement(o);
			} else {
				vec2.addElement(o);
			}
		}

		System.out.println(vec1);
		System.out.println(vec2);



ただ、この場合もループの外で ValueObject をインスタンス化すると、全ての要素が「どらえもん」で汚染されます。
以下、駄目な例です。
コード:
		ValueObject o = new ValueObject(null, null);

		while (e.hasMoreElements()) {
			String key = (String) e.nextElement();
			String value = (String) has1.get(key);
			o.no = key;
			o.naiyo = value;
			if (key.equals("4") || key.equals("5")) {
				vec1.addElement(o);
			} else {
				vec2.addElement(o);
			}
		}



この例で、発生していた現象が理解し易くなるのではないかと思います。
しん
常連さん
会議室デビュー日: 2004/04/04
投稿数: 48
投稿日時: 2004-04-12 00:40
なるほど!!ハッシュテーブルのオブジェクトの中身が置き換えられるか置き換えられない
かはキーが左右していたのですね。あと、サンプルを書いてくださいましてありがとうござい
ます。大変参考になりました。今後活用させていただきたいと思います。
お答えくださいましたunibonさん、でゅうくさん本当にありがとうございました。
1

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