读取 txt 文件并将数据存储在 java 中的哈希表中
read txt file and store data in a hashtable in java
我正在读取一个 txt 文件并将数据存储在哈希表中,但无法获得正确的输出。像这样的 txt 文件(部分)附上图片
this is part of my data
并且我想将第1列和第2列作为键(String类型)存储在哈希表中,将第3列和第4列作为值(ArrayList类型)存储在哈希表中。
我的代码如下:
private Hashtable<String, ArrayList<String[]>> readData() throws Exception {
BufferedReader br = new BufferedReader (new FileReader("MyGridWorld.txt"));
br.readLine();
ArrayList<String[]> value = new ArrayList<String[]>();
String[] probDes = new String[2];
String key = "";
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//System.out.println("line ="+line);
String source;
String action;
//split by tab
String [] splited = line.split("\t");
source = splited[0];
action = splited[1];
key = source+","+action;
probDes[0] = splited[2];
probDes[1] = splited[3];
value.add(probDes);
hashTableForWorld.put(key, value);
System.out.println("hash table is like this:" +hashTableForWorld);
}
br.close();
return hashTableForWorld;
}
输出如下所示:
it's a very long long line
我想也许哈希表坏了,但我不知道为什么。感谢您阅读我的问题。
Hashtable
和 ArrayList
(以及其他集合)不会复制键和值,因此您存储的所有值都与您分配的 probDes
数组相同在开始时(请注意,String[]
以神秘的形式出现是正常的,你必须自己让它变得漂亮,但你仍然可以看到它一直都是同样神秘的东西)。
可以肯定的是,您应该为循环内的每个元素分配一个新的 probDes
。
根据您的数据,我认为您可以使用数组作为值,ArrayList 没有实际用途
而value
也是一样,遇到新的key
:
就得单独分配
private Hashtable<String, ArrayList<String[]>> readData() throws Exception {
try(BufferedReader br=new BufferedReader(new FileReader("MyGridWorld.txt"))) {
br.readLine();
Hashtable<String, ArrayList<String[]>> hashTableForWorld=new Hashtable<>();
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//System.out.println("line ="+line);
String source;
String action;
//split by tab
String[] split = line.split("\t");
source = split[0];
action = split[1];
String key = source+","+action;
String[] probDesRew = new String[3];
probDesRew[0] = split[2];
probDesRew[1] = split[3];
probDesRew[2] = split[4];
ArrayList<String[]> value = hashTableForWorld.get(key);
if(value == null){
value = new ArrayList<>();
hashTableForWorld.put(key, value);
}
value.add(probDesRew);
}
return hashTableForWorld;
}
}
除了将变量重新定位到它们的实际使用位置之外,return 值也在本地创建,并且 reader 被包装到一个 try-with-resource 结构中,以确保它是即使发生异常也关闭(参见官方教程here)。
我们首先要确定的是你有一个非常明显的 XY-Problem,因为 "what you need to do" 和 "how you're trying to solve it" 完全不一致。
所以让我们回到最初的问题,首先尝试找出我们需要的东西。
据我所知,source
和 action
是相关联的,因为它们代表您的数据结构的可查询 "keys",而 probability
、destination
和 reward
在您的数据结构中是可查询的 "outcomes"。因此,我们将首先创建对象来表示这两个概念:
public class SourceAction implements Comparable<SourceAction>{
public final String source;
public final String action;
public SourceAction() {
this("", "");
}
public SourceAction(String source, String action) {
this.source = source;
this.action = action;
}
public int compareTo(SourceAction sa) {
int comp = source.compareTo(sa.source);
if(comp != 0) return comp;
return action.compareto(sa.action);
}
public boolean equals(SourceAction sa) {
return source.equals(sa.source) && action.equals(sa.action);
}
public String toString() {
return source + ',' + action;
}
}
public class Outcome {
public String probability; //You can use double if you've written code to parse the probability
public String destination;
public String reward; //you can use double if you're written code to parse the reward
public Outcome() {
this("", "", "");
}
public Outcome(String probability, String destination, String reward) {
this.probability = probability;
this.destination = destination;
this.reward = reward;
}
public boolean equals(Outcome o) {
return probability.equals(o.probability) && destination.equals(o.destination) && reward.equals(o.reward);
public String toString() {
return probability + ',' + destination + ',' + reward;
}
}
那么,给定这些对象,什么样的数据结构可以适当地封装这些对象之间的关系,假设一个SourceAction
似乎有一个一对多 与 Outcome
对象的关系?我的建议是一个Map<SourceAction, List<Outcome>>
代表这种关系。
private Map<SourceAction, List<Outcome>> readData() throws Exception {
可以使用散列 Table(在本例中为 HashMap
)来包含这些对象,但我试图使代码尽可能简单,所以我们'我们将继续使用更通用的界面。
然后,我们可以重用您在原始代码中使用的逻辑,通过一些调整将值插入此数据结构。
private Map<SourceAction, List<Outcome>> readData() {
//We're using a try-with-resources block to eliminate the later call to close the reader
try (BufferedReader br = new BufferedReader (new FileReader("MyGridWorld.txt"))) {
br.readLine();//Skip the first line because it's just a header
//I'm using a TreeMap because that makes the implementation simpler. If you absolutely
//need to use a HashMap, then make sure you implement a hash() function for SourceAction
Map<SourceAction, List<Outcome>> dataStructure = new TreeMap<>();
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//split by tab
String [] splited = line.split("\t");
SourceAction sourceAction = new SourceAction(splited[0], splited[1]);
Outcome outcome = new Outcome(splited[2], splited[3], splited[4]);
if(dataStructure.contains(sourceAction)) {
//Entry already found; we're just going to add this outcome to the already
//existing list.
dataStructure.get(sourceAction).add(outcome);
} else {
List<Outcome> outcomes = new ArrayList<>();
outcomes.add(outcome);
dataStructure.put(sourceAction, outcomes);
}
}
} catch (IOException e) {//Do whatever, or rethrow the exception}
return dataStructure;
}
然后,如果你想查询与给定源+动作关联的所有结果,你只需要构造一个SourceAction
对象并为它查询Map。
Map<SourceAction, List<Outcome>> actionMap = readData();
List<Outcome> outcomes = actionMap.get(new SourceAction("(1,1)", "Up"));
assert(outcomes != null);
assert(outcomes.size() == 3);
assert(outcomes.get(0).equals(new Outcome("0.8", "(1,2)", "-0.04")));
assert(outcomes.get(1).equals(new Outcome("0.1", "(2,1)", "-0.04")));
assert(outcomes.get(2).equals(new Outcome("0.1", "(1,1)", "-0.04")));
这应该会产生您需要解决您的问题的功能。
您应该更改添加到哈希表的逻辑以检查您创建的密钥。如果该键存在,则获取它映射到的数组的数组列表并将您的数组添加到其中。目前您将覆盖数据。
试试这个
if(hashTableForWorld.containsKey(key))
{
value = hashTableForWorld.get(key);
value.add(probDes);
hashTableForWorld.put(key, value);
}
else
{
value = new ArrayList<String[]>();
value.add(probDes);
hashTableForWorld.put(key, value);
}
然后打印内容尝试这样的事情
for (Map.Entry<String, ArrayList<String[]>> entry : hashTableForWorld.entrySet()) {
String key = entry.getKey();
ArrayList<String[]> value = entry.getValue();
System.out.println ("Key: " + key + " Value: ");
for(int i = 0; i < value.size(); i++)
{
System.out.print("Array " + i + ": ");
for(String val : value.get(i))
System.out.print(val + " :: ")
System.out.println();
}
}
我正在读取一个 txt 文件并将数据存储在哈希表中,但无法获得正确的输出。像这样的 txt 文件(部分)附上图片 this is part of my data
并且我想将第1列和第2列作为键(String类型)存储在哈希表中,将第3列和第4列作为值(ArrayList类型)存储在哈希表中。 我的代码如下:
private Hashtable<String, ArrayList<String[]>> readData() throws Exception {
BufferedReader br = new BufferedReader (new FileReader("MyGridWorld.txt"));
br.readLine();
ArrayList<String[]> value = new ArrayList<String[]>();
String[] probDes = new String[2];
String key = "";
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//System.out.println("line ="+line);
String source;
String action;
//split by tab
String [] splited = line.split("\t");
source = splited[0];
action = splited[1];
key = source+","+action;
probDes[0] = splited[2];
probDes[1] = splited[3];
value.add(probDes);
hashTableForWorld.put(key, value);
System.out.println("hash table is like this:" +hashTableForWorld);
}
br.close();
return hashTableForWorld;
}
输出如下所示: it's a very long long line
我想也许哈希表坏了,但我不知道为什么。感谢您阅读我的问题。
Hashtable
和 ArrayList
(以及其他集合)不会复制键和值,因此您存储的所有值都与您分配的 probDes
数组相同在开始时(请注意,String[]
以神秘的形式出现是正常的,你必须自己让它变得漂亮,但你仍然可以看到它一直都是同样神秘的东西)。
可以肯定的是,您应该为循环内的每个元素分配一个新的 probDes
。
根据您的数据,我认为您可以使用数组作为值,ArrayList 没有实际用途
而value
也是一样,遇到新的key
:
private Hashtable<String, ArrayList<String[]>> readData() throws Exception {
try(BufferedReader br=new BufferedReader(new FileReader("MyGridWorld.txt"))) {
br.readLine();
Hashtable<String, ArrayList<String[]>> hashTableForWorld=new Hashtable<>();
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//System.out.println("line ="+line);
String source;
String action;
//split by tab
String[] split = line.split("\t");
source = split[0];
action = split[1];
String key = source+","+action;
String[] probDesRew = new String[3];
probDesRew[0] = split[2];
probDesRew[1] = split[3];
probDesRew[2] = split[4];
ArrayList<String[]> value = hashTableForWorld.get(key);
if(value == null){
value = new ArrayList<>();
hashTableForWorld.put(key, value);
}
value.add(probDesRew);
}
return hashTableForWorld;
}
}
除了将变量重新定位到它们的实际使用位置之外,return 值也在本地创建,并且 reader 被包装到一个 try-with-resource 结构中,以确保它是即使发生异常也关闭(参见官方教程here)。
我们首先要确定的是你有一个非常明显的 XY-Problem,因为 "what you need to do" 和 "how you're trying to solve it" 完全不一致。
所以让我们回到最初的问题,首先尝试找出我们需要的东西。
据我所知,source
和 action
是相关联的,因为它们代表您的数据结构的可查询 "keys",而 probability
、destination
和 reward
在您的数据结构中是可查询的 "outcomes"。因此,我们将首先创建对象来表示这两个概念:
public class SourceAction implements Comparable<SourceAction>{
public final String source;
public final String action;
public SourceAction() {
this("", "");
}
public SourceAction(String source, String action) {
this.source = source;
this.action = action;
}
public int compareTo(SourceAction sa) {
int comp = source.compareTo(sa.source);
if(comp != 0) return comp;
return action.compareto(sa.action);
}
public boolean equals(SourceAction sa) {
return source.equals(sa.source) && action.equals(sa.action);
}
public String toString() {
return source + ',' + action;
}
}
public class Outcome {
public String probability; //You can use double if you've written code to parse the probability
public String destination;
public String reward; //you can use double if you're written code to parse the reward
public Outcome() {
this("", "", "");
}
public Outcome(String probability, String destination, String reward) {
this.probability = probability;
this.destination = destination;
this.reward = reward;
}
public boolean equals(Outcome o) {
return probability.equals(o.probability) && destination.equals(o.destination) && reward.equals(o.reward);
public String toString() {
return probability + ',' + destination + ',' + reward;
}
}
那么,给定这些对象,什么样的数据结构可以适当地封装这些对象之间的关系,假设一个SourceAction
似乎有一个一对多 与 Outcome
对象的关系?我的建议是一个Map<SourceAction, List<Outcome>>
代表这种关系。
private Map<SourceAction, List<Outcome>> readData() throws Exception {
可以使用散列 Table(在本例中为 HashMap
)来包含这些对象,但我试图使代码尽可能简单,所以我们'我们将继续使用更通用的界面。
然后,我们可以重用您在原始代码中使用的逻辑,通过一些调整将值插入此数据结构。
private Map<SourceAction, List<Outcome>> readData() {
//We're using a try-with-resources block to eliminate the later call to close the reader
try (BufferedReader br = new BufferedReader (new FileReader("MyGridWorld.txt"))) {
br.readLine();//Skip the first line because it's just a header
//I'm using a TreeMap because that makes the implementation simpler. If you absolutely
//need to use a HashMap, then make sure you implement a hash() function for SourceAction
Map<SourceAction, List<Outcome>> dataStructure = new TreeMap<>();
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//split by tab
String [] splited = line.split("\t");
SourceAction sourceAction = new SourceAction(splited[0], splited[1]);
Outcome outcome = new Outcome(splited[2], splited[3], splited[4]);
if(dataStructure.contains(sourceAction)) {
//Entry already found; we're just going to add this outcome to the already
//existing list.
dataStructure.get(sourceAction).add(outcome);
} else {
List<Outcome> outcomes = new ArrayList<>();
outcomes.add(outcome);
dataStructure.put(sourceAction, outcomes);
}
}
} catch (IOException e) {//Do whatever, or rethrow the exception}
return dataStructure;
}
然后,如果你想查询与给定源+动作关联的所有结果,你只需要构造一个SourceAction
对象并为它查询Map。
Map<SourceAction, List<Outcome>> actionMap = readData();
List<Outcome> outcomes = actionMap.get(new SourceAction("(1,1)", "Up"));
assert(outcomes != null);
assert(outcomes.size() == 3);
assert(outcomes.get(0).equals(new Outcome("0.8", "(1,2)", "-0.04")));
assert(outcomes.get(1).equals(new Outcome("0.1", "(2,1)", "-0.04")));
assert(outcomes.get(2).equals(new Outcome("0.1", "(1,1)", "-0.04")));
这应该会产生您需要解决您的问题的功能。
您应该更改添加到哈希表的逻辑以检查您创建的密钥。如果该键存在,则获取它映射到的数组的数组列表并将您的数组添加到其中。目前您将覆盖数据。
试试这个
if(hashTableForWorld.containsKey(key))
{
value = hashTableForWorld.get(key);
value.add(probDes);
hashTableForWorld.put(key, value);
}
else
{
value = new ArrayList<String[]>();
value.add(probDes);
hashTableForWorld.put(key, value);
}
然后打印内容尝试这样的事情
for (Map.Entry<String, ArrayList<String[]>> entry : hashTableForWorld.entrySet()) {
String key = entry.getKey();
ArrayList<String[]> value = entry.getValue();
System.out.println ("Key: " + key + " Value: ");
for(int i = 0; i < value.size(); i++)
{
System.out.print("Array " + i + ": ");
for(String val : value.get(i))
System.out.print(val + " :: ")
System.out.println();
}
}