为什么我的地图合并函数会合并所有内容



我有一个相当简单的Go程序,它可以确定某人的事件时间表是否有重叠。本质上这就是它的作用:

我们有3个活动,比如说一家杂货店:

            day   0  1  2  3  4  5     
apple sale        [-----------]
banana sale             [--------]
pickle sale                [-------------]

这是我的代码:

package main
import (
    "fmt"
)
type event struct {
    start int
    end int
    groups map[string]bool
}
func main(){
    //Create Events
    campaigns := []event{
        event{
            start: 0,
            end: 4,
            groups: map[string]bool{
                "apple sale": true,
            },
        },
        event{
            start: 2,
            end: 5,
            groups: map[string]bool{            
                "banna sale": true,         
            },
        },
        event{
            start: 3,
            end: 10,
            groups: map[string]bool{
                "pickle sale": true,
            },
        },
    }
    fmt.Printf("n-------------n| Events    |n-------------nn")
    for _, c := range campaigns {
        fmt.Printf("Name: ")
        for name, _ := range c.groups {
            fmt.Printf("%v, ", name)
        }
        fmt.Printf("nStart:%vnEnd:%vnn", c.start, c.end)
    }
    overlaps := recursiveOverlaps(campaigns, make([]event, 0))
    fmt.Printf("n-------------n| Overlaps  |n-------------nn")
    for _, c := range overlaps {
        fmt.Printf("Events: ")
        for name, _ := range c.groups {
            fmt.Printf("%v, ", name)
        }
        fmt.Printf("nStart:%vnEnd:%vnn", c.start, c.end)
    }
}
func recursiveOverlaps(events []event, overlaps []event) []event {
    //pop comparisonEvent (first item in array)
    comparisonEvent, events := events[len(events)-1], events[:len(events)-1]

    if len(events) == 0 {//check base case
        return overlaps;
    }
    //Find overlaps
    for _, eventItem := range events {
        overlaping, overlapCase := overlapExists(comparisonEvent, eventItem)
        if overlaping {
            groups := mergeKeys(comparisonEvent.groups, eventItem.groups)
            switch overlapCase {
                case 1:
                    overlaps = append( overlaps, event{eventItem.start, eventItem.end, groups} )
                case 2:
                    overlaps = append( overlaps, event{comparisonEvent.start, comparisonEvent.end, groups} )
                case 3:
                    overlaps = append( overlaps, event{eventItem.start, comparisonEvent.end, groups} )
                case 4:
                    overlaps = append( overlaps, event{comparisonEvent.start, eventItem.end, groups} )
            }
            //reset groups so we don't get any funny business
            groups = map[string]bool{}
        }
    }
    return recursiveOverlaps(events, overlaps)
}
func overlapExists(a event, b event) (bool, int) {
    if between(a.start, a.end, b.start) && between(a.start, a.end, b.end) {
    // [----------]
    //    [-----]
        return true, 1
    }
    if between(b.start, b.end, a.start) && between(b.start, b.end, a.end) {
    //    [-----]
    // [----------]
        return true, 2
    }
    if between(a.start, a.end, b.start) {
    // [----------]
    //    [--------------
        return true, 3
    }
    if between(a.start, a.end, b.end) {
    //            [----------]
    //    --------------]
        return true, 4
    }
    return false, 0
}
func between(a, b, c int) bool {
    //is c between a and b?
    if c > a && c < b {
        return true
    }
    return false
}
// Given two maps merge right into left
func mergeKeys(left, right map[string]bool) map[string]bool {
    for key, rightVal := range right {
        left[key] = rightVal
    }
    return left
}

代码几乎工作。。。。但问题是,从逻辑上讲,我把它编程为只比较两个事件。不是一次三个。然而,结果是:

-------------
| Events    |
-------------
Name: apple sale,
Start:0
End:4
Name: banna sale,
Start:2
End:5
Name: car sale,
Start:3
End:10

-------------
| Overlaps  |
-------------
Events: banna sale, car sale, apple sale,
Start:3
End:4
Events: car sale, apple sale, banna sale,
Start:3
End:5
Events: banna sale, apple sale,
Start:2
End:4

不知怎么的,我觉得mergeKeys()函数在做一些奇怪的事情。有什么想法吗?

好的。所以我发现了问题所在:

go中的地图是通过引用传递的。。。。有点不是

即使地图前面没有指针。。。它们是通过引用传递的。。。有点事实并非如此,但你可以在这篇文章中读到更多关于这一点的内容,";在go"中没有通过引用;以及这篇文章;如果映射不是引用变量,它是什么;。我将给你这段摘录,以澄清正在发生的事情:

map值是指向runtime.hmap结构的指针。

即使映射不是通过引用传递的,而是通过值传递的。。。传递到函数中的原始映射变量将被修改。这意味着,当我在mergeKeys函数中更改左侧映射时,我实际上也在更改comparisonEvent.groups映射。

为了解释这一点,我创建了一个垃圾图,我可以变异,不会产生任何后果:

if overlaping {
    trashMap := make(map[string]bool)
    for key, value := range comparisonEvent.groups {
        trashMap[key] = value
    }
    
    groups := mergeKeys(trashMap, eventItem.groups)
    switch overlapCase {
    
        case 1:
            overlaps = append( overlaps, event{eventItem.start, eventItem.end, groups} )
        case 2:
            overlaps = append( overlaps, event{comparisonEvent.start, comparisonEvent.end, groups} )
        case 3:
            overlaps = append( overlaps, event{eventItem.start, comparisonEvent.end, groups} )
        case 4:
            overlaps = append( overlaps, event{comparisonEvent.start, eventItem.end, groups} )
    }
}

在我接受这个答案之前,我仍然愿意讨论和更好的解决方案。我希望这能帮助到外面的人!

最新更新