【问题标题】:How to add to an ArrayList that is a HashMap value while iterating?迭代时如何添加到作为 HashMap 值的 ArrayList?
【发布时间】:2017-06-12 18:26:34
【问题描述】:

我有一个 HashMap,键的值是一个 ArrayList。当我逐行读取文件时,我需要添加到属于该特定键的 ArrayList 中。 该文件可能有 1 行或 100 万行,键名将是行(字符串),它的值将表示它在文件中出现的行号。

有人可以帮帮我吗?此外,这种快速的时间复杂性是否明智?如果不是,我该如何优化?

示例 test.txt:

Hello        <== Line 0
Jello        <== Line 1
Mello        <== Line 2
Hello        <== Line 3
Tello        <== Line 4
Jello        <== Line 5
Tello        <== Line 6
Tello        <== Line 7

我需要我的地图存储什么(忽略顺序):

{"Hello": [0, 3]}
{"Jello": [1, 5]}
{"Mello": [2]}
{"Tello": [4, 6, 7]}

我的代码是:

ArrayList<Integer> al = new ArrayList<Integer>();
Map<String, ArrayList<Integer>> hm = new HashMap<String, ArrayList<Integer>>();

int num = 0;
for (String line = file.readLine(); line != null; line = file.readLine()) {
    map.put(line, al.add(num)); <== the issue is here, how to fix?
}

编译错误:

incompatible types: boolean cannot be converted to ArrayList<Integer>

【问题讨论】:

  • 单独调用al.add(num);,然后使用map.put(line, num);

标签: java performance data-structures hashmap big-o


【解决方案1】:

您的问题是数组列表上的add 方法返回一个布尔值。

您正在尝试做一个“concordance”应用程序,并且很容易在 Web 上搜索 Java 中的解决方案。这个问题的其他答案很好地说明了这一点。

关于您的复杂性问题,使用键是单词且值是行号数组列表的哈希映射非常好(并且应该具有接近最佳的复杂性,因为每个行处理都需要摊销的常数时间)。然而,只要一切都适合记忆,情况就是如此!如果您的单词文件数不胜数,您可以使用中间文件与良好的 map-reduce 框架进行协调。

【讨论】:

  • 这是一个很好的解释。我很高兴我想对了。谢谢!
【解决方案2】:

Java 8:

map.computeIfAbsent(line, k -> new ArrayList<>()).add(num);

Java 7:

ArrayList<Integer> values = map.get(line);
if (values == null) {
    map.put(line, values = new ArrayList<>());
}
values.add(num);

【讨论】:

  • 这对我不起作用。列表的长度是正确的,但它的元素总是 0。
  • @udpcon just values.add(num++)
  • @udpcon 您显然必须增加num。那不是问题。
  • 这个答案实际上更好。 Java 8 部分。
  • 我的坏,愚蠢的我。我真的很喜欢这个答案。我都喜欢。谢谢。
【解决方案3】:

ArrayList 的 add 函数返回一个布尔值,表示成功或失败。这就是您收到错误的原因。您必须先将您的号码添加到列表中,然后将列表放入地图中。但是您的代码中存在不同的问题。您将一遍又一遍地向所有键添加相同的列表。

试试这个代码:

Map<String, ArrayList<Integer>> hm = new HashMap<String, ArrayList<Integer>>();
int currentLineNumber = 0;
for (String line = file.readLine(); line != null; line = file.readLine()) {

    if(!hm.containsKey(line))
    {
        hm.put(line, new ArrayList<Integer>());
    }

    hm.get(line).add(currentLineNumber);

    currentLineNumber++;
}

【讨论】:

【解决方案4】:

您正在做的是将整数添加到 HashMap 键而不是整个 ArrayList

试试这样的:

            Map<String, ArrayList<Integer>> hm = new HashMap<String, ArrayList<Integer>>();

            String key="";
            while(file.readLine()!=null){
              key=file.readLine();  
      ArrayList<Integer> al = new ArrayList<Integer>();

          OUT: for (String line = file.readLine(); line != null; line = file.readLine()) { 
if(key.equals(line)){
              al.add(num);
  }
    else{
     break OUT;
}
}
             map.put(key, al);
        }

此解决方案尚未经过测试,但我认为这会起作用。

【讨论】:

  • 这看起来不会编译。
  • 我忘了在 while 中添加右括号.. 我更正了.. 现在试试
  • 不,我的意思是“key=line”。行仅适用于 for 循环。
  • 对此感到抱歉.. 请立即查看.. 更新了我的答案
  • 这将编译但逻辑有缺陷。请记住,while 循环中的文件与 for 循环中的文件相同。因此 for 循环最终会将文件读取到最后,这意味着不需要 while 循环。还要记住,您总是添加到同一个数组列表中。因此,您最终将拥有一个包含所有数字的列表。但是您的基本想法是正确的,您首先要在哪里构建列表然后添加它。
【解决方案5】:
Integer num = 0;
for (String line = file.readLine(); line != null; line = file.readLine()) {

    if(!hm.containsKey(line))
    {
        hm.put(line, new ArrayList<Integer>());
    }

    hm.get(line).add(num);

    num++;
}

我认为这应该可行。

【讨论】:

    猜你喜欢
    • 2021-07-31
    • 1970-01-01
    • 2016-09-08
    • 1970-01-01
    • 2011-12-02
    • 1970-01-01
    • 1970-01-01
    • 2021-02-22
    • 1970-01-01
    相关资源
    最近更新 更多