繁体   English   中英

读取txt文件并将数据存储在Java中的哈希表中

[英]read txt file and store data in a hashtable in java

我正在读取txt文件,并将数据存储在哈希表中,但无法获得正确的输出。 像这样(部分)的txt文件附加的图片, 这是我的数据的一部分

我想将列1和列2存储为哈希表中的键(字符串类型),将列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;


}

输出如下所示: 这是一条很长很长的线

我认为哈希表可能已损坏,但我不知道为什么。 感谢您阅读我的问题。

我们需要确定的第一件事是您确实有一个明显的XY问题 ,即“您需要做什么”和“您要如何解决它”完全是矛盾的。

因此,让我们回到最初的问题,并尝试先解决我们需要的东西。

尽我所能确定, sourceaction是相互联系的,因为它们表示数据结构中可查询的“键”,而probabilitydestinationreward是数据结构中可查询的“结果”。 因此,我们将从创建代表这两个概念的对象开始:

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 {

可以使用哈希表(在本例中为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;
}

然后,如果要查询与给定的source + action相关的所有结果,则只需构造SourceAction对象并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")));

这应该可以解决您的问题所需的功能。

HashtableArrayList (及其他集合)不会复制键和值,因此,您存储的所有值都是开头分配的同一个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;
    }
}

除了将变量重定位到实际使用位置之外,还在本地创建返回值,并且将阅读器包装到try-with-resource结构中,以确保即使发生异常也将其关闭(请参见此处的官方教程)。 。

您应该更改添加到哈希表中的逻辑,以检查您创建的密钥。 如果键存在,则获取其映射到的阵列的阵列列表,然后将阵列添加到其中。 当前,您将覆盖数据。

尝试这个

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();
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM