【问题标题】:How to map List of KVP to Map<Key, List<Value>> .. fast如何将 KVP 列表映射到 Map<Key, List<Value>> .. 快速
【发布时间】:2013-03-08 18:31:17
【问题描述】:

我很快就写了这个 sn-p 来完成这项工作

private void map() {
    for (KVPair kvPair : content) {
        String k = kvPair.getKey();
        String v = kvPair.getValue();

        if (mappedContent.containsKey(k)) {
            List<String> values = mappedContent.get(k);
            values.add(v);
        } else {
            List<String> values = new ArrayList<>();
            values.add(v);
            mappedContent.put(k, values);
        }
    }
}

它有效,当运行 1k、2k、4k 和 8k 随机数据时,我得到以下性能(平均 100,000 次运行)

Running with 1,000 pairs
  [perfRun] 100000 iterations took 3 seconds
  [perfRun] Run time: 3758786000 ns. 1 iteration takes 37 us
Running with 2,000 pairs
  [perfRun] 100000 iterations took 6 seconds
  [perfRun] Run time: 6675544000 ns. 1 iteration takes 66 us
Running with 4,000 pairs
  [perfRun] 100000 iterations took 13 seconds
  [perfRun] Run time: 13337145000 ns. 1 iteration takes 133 us
Running with 8,000 pairs
  [perfRun] 100000 iterations took 27 seconds
  [perfRun] Run time: 27109480000 ns. 1 iteration takes 271 us

粗略地说,当大小翻倍时,时间也会翻倍。我会采用线性增长,但仍然想知道,我们能做得更好吗?是否可以使用恒定时间映射事物?

【问题讨论】:

  • 也许你告诉我们你在做什么。
  • 您是否尝试过使用公共集合 MultiValueMap 而不是自己滚动?

标签: java performance algorithm


【解决方案1】:

我所看到的,mappedContent.containsKey(k) 是不必要的,大致需要BigO(n),您可以通过null 进行检查,

for (KVPair kvPair : content) {
        String k = kvPair.getKey();
        String v = kvPair.getValue();
        List<String> values = mappedContent.get(k);
        if (values!=null) {
            values.add(v);
        } else {
            values = new ArrayList<>();
            values.add(v);
            mappedContent.put(k, values);
        }
}

【讨论】:

    【解决方案2】:

    根据@Quoi 的回答,不知道在 null 检查后保存 else 块是否有区别

    for (KVPair kvPair : content) {
        String k = kvPair.getKey();
        List<String> values = mappedContent.get(k);
        if (values == null) {
            values = new ArrayList<>();
            mappedContent.put(k, values);
        }
        values.add(kvPair.getValue());
    }
    

    您还可以对列表的大小做出一些假设,以便将该大小传递给列表构造函数并节省列表需要重新调整大小的时间。如果内存不是问题,您可以将content.size() + 1 作为列表的大小。

    【讨论】:

    • 太棒了!但是你能告诉我你到底做了什么来获得这种提升吗?大小猜测或没有其他?
    • 我运行了 1,2,4,8000 个随机生成对的样本。仅计时此方法
    【解决方案3】:

    除非你能改变底层的数据结构,否则你不能做得比线性时间更好。

    考虑一下:您有一个包含 n 个唯一条目的列表。要映射每个必须访问的一个。假设访问成本为 1。那么必须有 n 次访问。因此,您的复杂度为 n * 1 = n,或您的基准测试指出的线性时间。

    现在,如果您有一个数据结构,可以共享数据但同时提供两个接口,那么您可以实现在两者之间切换的恒定时间。显然,您的静态类型与您的示例不同。

    【讨论】:

      猜你喜欢
      • 2011-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-08
      • 2018-01-29
      • 2015-05-15
      • 2020-10-04
      相关资源
      最近更新 更多