如何进行分组,然后在Go

时间:2017-12-14 18:45:50

标签: go slice

对不起,这是我的第一个Stackoverflow问题,所以,除了一些帮助之外,关于我可以做些什么来改进它的任何提示/建议都会很棒。

问题:

我有一个切片,我试图按某些标准分组成更小的切片。然后,如果它们在切片中包含任何相同的值,则需要将新创建的切片彼此合并。 (基本上,将切片附加到具有"重叠"值的切片)。

有关此问题的一些其他说明:

  • 原始切片中的项目数可能在1-50之间,在大多数情况下,异常值很少超过100。

  • 一旦开始,内部'内部的大小。切片将介于1-10个值之间。

  • 性能是一个因素,因为此操作将作为Web服务的一部分运行,其中单个请求将执行此操作20次以上,并且峰值每分钟可能有多个(数十万)请求倍。但是,代码的清晰度也很重要。

  • 我的实现是使用整数,最终的实现将有更复杂的结构,虽然我正在考虑制作一个地图,然后根据键使用下面显示的实现。 这是个好主意吗?

我已将问题分解为几个步骤:

  1. 根据标准(初始分组阶段)
  2. 创建具有值分组的2D切片
  3. 如果切片包含重复的值,则尝试合并切片。
  4. 我遇到两个问题:

    首先,我认为我的实现可能不会很好地扩展,因为它往往有一些嵌套循环(但是,这些循环将在小切片上迭代,所以这可能没问题)

    其次,我的实现需要在最后添加一个额外的步骤来删除重复的值,理想情况下我们应该删除它。

    输入 [100,150,300,350,600,700] 预期产出: [[100 150 300 350] [600 700]]

    这是根据'选择标准'对切​​片中至少一个其他值的150个单位内的值进行分组。

    代码Go Playground link

    package main
    
    import (
        "fmt"
        "sort"
    )
    
    func filter(vs []int, f func(int) bool) []int {
        vsf := make([]int, 0)
        for _, v := range vs {
            if f(v) {
                vsf = append(vsf, v)
            }
        }
        return vsf
    }
    
    func unique(intSlice []int) []int {
        keys := make(map[int]bool)
        list := []int{} 
        for _, entry := range intSlice {
            if _, value := keys[entry]; !value {
                keys[entry] = true
                list = append(list, entry)
            }
        }    
        return list
    }
    
    func contains(intSlice []int, searchInt int) bool {
        for _, value := range intSlice {
            if value == searchInt {
                return true
            }
        }
        return false
    }
    
    func compare(a, b []int) bool {
        if len(a) != len(b) {
            return false
        }
    
        if (a == nil) != (b == nil) {
            return false
        }
    
        b = b[:len(a)] 
        for i, v := range a {
            if v != b[i] { 
                return false
            }
        }
    
        return true
    }
    
    
    
    func main() {
        fmt.Println("phase 1 - initial grouping")
        s := []int{100, 150, 300, 350, 600, 700}
        g := make([][]int, 0)
    
        // phase 1
        for _, v := range s {
            t := filter(s, func(i int) bool { return i - v >= -150 && i - v <= 150 })
            for _, v1 := range t {
                t1 := filter(s, func(i int) bool { return i - v1 >= -150 && i - v1 <= 150})
                t = unique(append(t, t1...))
                sort.Ints(t)
            }
    
            g = append(g, t)
            fmt.Println(g)
        }
        // phase 2
        fmt.Println("phase 2 - merge in place")
    
        for i, tf := range g {
            for _, death := range tf {
                if i < len(g) - 1 && contains(g[i+1], death) {
                    g[i+1] = unique(append(g[i], g[i+1]...))
                    g = g[i+1:] 
                } else if i == len(g) - 1 {
                    fmt.Println(g[i], g[i-1])
                    // do some cleanup to make sure the last two items of the array don't include duplicates
                    if compare(g[i-1], g[i]) {
                        g = g[:i]
                    }
                }
            }
            fmt.Println(i, g)
        }
    }
    

1 个答案:

答案 0 :(得分:1)

不确定您实际问的是什么,问题尚未完全定义。 所以这是一个效率更高的版本

如果输入没有排序且输出顺序很重要,那么这是一个糟糕的解决方案。

这是(on Play

package main

import (
    "fmt"
)

// Input: [ 100, 150, 300, 350, 600, 700 ] Expected Output: [[100 150 300 350] [600 700]]

func main() {
    input := []int{100, 150, 300, 350, 600, 700}

    fmt.Println("Input:", input)
    fmt.Println("Output:", groupWithin150(input))
}

func groupWithin150(ints []int) [][]int {
    var ret [][]int
    // Your example input was sorted, if the inputs aren't actually sorted, then uncomment this
    // sort.Ints(ints)
    var group []int
    for idx, i := range ints {
        if idx > 0 && i-150 > group[len(group)-1] {
            ret = append(ret, group)
            group = make([]int, 0)
        }
        group = append(group, i)
    }
    if len(group) > 0 {
        ret = append(ret, group)
    }
    return ret
}