【问题标题】:Count distinct values in array - performance tips计算数组中的不同值 - 性能提示
【发布时间】:2017-11-09 02:49:24
【问题描述】:

我在优化 go 地图时遇到了一些问题。
我想在字符串数组中生成一个频率表(计算不同的出现次数)。我的代码非常适合小型数组,但是当我开始使用 100k+ 结构(具有许多不同的值)时,它的性能还不够。

现在,我的方法是生成一个具有不同值的数组,比较值并增加计数器变量(映射到字符串)。

    counter := make( map[string]int )    
    for _, distinct := range distinctStrArray{
        for _, row := range StrArray{
            if (row == distinct){
                counter[distinct]++
            }  
        } 
    }

我尝试了另一种方法,其中输入数组之前已排序(以尽量减少对地图的更改次数)。这有点快。

    count:=0
    for _, distinct := range distinctStrArray{
        for _, row := range StrArray{
            if (row == distinct){
                count++
            }  
        } 
    counter[distinct] += count
    count= 0
    } 

你对我可以做些什么来优化一个简单的 count(distinct) 类型问题有什么建议吗...?我对任何事情都持开放态度。
谢谢!

【问题讨论】:

  • 在第二个示例中,您在找到匹配项后继续迭代,如果输入已排序,则这是不必要的。如果row != distinct && count > 0 可以中断,因为这将是找到匹配项后的第一个不匹配项,并且如果输入已排序,则此后将不会有任何匹配项。
  • 拥有两个数组的目的是什么? map 已经保证了不同的键,为什么不直接使用呢?

标签: go count maps


【解决方案1】:

如果没有更多上下文,我会转储不同值的单独数组 - 生成它需要时间,并且使用它需要嵌套循环。假设第二个数组没有其他用途,我会使用类似的东西:

counter := make( map[string]int )    
for _, row := range StrArray {
    counter[row]++
} 

如果您出于某些单独目的需要不带计数的不同字符串列表,您可以在之后轻松获得它:

distinctStrings := make([]string, len(counter))
i := 0
for k := range counter {
    distinctStrings[i] = k
    i++
}

迭代不同字符串的数组是 O(n),而按键访问 map 是 O(log(n))。这将你的整体从 O(n^2) 带到 O(n*log(n)),这对于更大的数据集应该是一个显着的改进。但是,与任何优化一样:测试、测量、分析、优化。

【讨论】:

  • 在 hashmaps 的情况下,按键访问通常是 O(1)。
  • O(1)... 是吗? Go 规范没有对性能做出任何声明。我想我应该说“不比 O(log(n)) 用于地图访问或总共 O(n*log(n)) 差”。此外,一些迭代不仅仅是查找,它们将是插入,由于重新平衡等原因,这往往需要更长的时间。无论如何......肯定比 O(n^2) 快。
猜你喜欢
  • 1970-01-01
  • 2022-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多