习惯用法比较2个切片,看看哪个元素已被删除

时间:2016-01-06 02:35:19

标签: go

我在我的应用程序中使用RethinkDB,我有一个拥有用户的大厅。

RethinkDB能够监视对表的更改,并且当更改发生时,它会自动发出更改,以便您可以使用数据执行任何操作,现在我尝试在用户离开时进行更改大厅我可以发送一个websocket来删除用户。唯一的问题是我试图找出前/后数据的差异,这是members的一个切片,这是数据:

type change struct {
    NewVal *fields `gorethink:"new_val,omitempty"`
    OldVal *fields `gorethink:"old_val,omitempty"`
}

type fields struct {
    ID      string `gorethink:"id"`
    Owner   string `gorethink:"owner"`
    Inqueue bool   `gorethink:"inqueue"`
    Members []struct {
        SteamID  string `gorethink:"steamid"`
        Username string `gorethink:"username"`
    } `gorethink:"members"`
    Messages []struct {
        Username  string    `gorethink:"username"`
        Message   string    `gorethink:"message"`
        CreatedAt time.Time `gorethink:"createdAt"`
    } `gorethink:"messages"`
}

现在我正在做

func (l *lobby) watchChanges() {
    db := common.DB()
    query := gorethink.Table("Lobbys").Get(l.ID).Changes()
    res, err := query.Run(db)
    if err != nil {
        log.Println(err)
    }

    go func(res *gorethink.Cursor, l *lobby) {
        defer res.Close()
        changes := new(change)
        for res.Next(&changes) {
            if changes.NewVal != nil && changes.OldVal != nil {
                switch {
                case len(changes.NewVal.Members) > len(changes.OldVal.Members):
                    // Member has joined so announce who it was.

                case len(changes.NewVal.Members) < len(changes.OldVal.Members):
                    // Member has left so announce who it was.
           -------->
                case len(changes.NewVal.Messages) > len(changes.OldVal.Messages):
                    // New Message was recieved so announce the message.

                }
            }
        }
    }(res, l)

    select {
    case <-l.KillMe:
        res.Close()
        break
    }
}

新条目非常简单我只需从片段中删除并发送,但是当用户离开时,如何比较changes.NewVal.Memberschanges.OldVal.Members看看哪个索引被删除了所以我可以发送正确的成员通过websocket删除。希望我的问题很清楚,如果不是,请告诉我。

这就是我目前正在做的事情

removedIndex := 0
for i, oldMember := range changes.OldVal.Members {
    foundMissing := true
    for _, newMember := range changes.NewVal.Members {
        if reflect.DeepEqual(oldMember, newMember) {
            foundMissing = false
        }
    }
    if foundMissing {
        removedIndex = i
        break
    }
}

但感觉有点hacky,有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

使用唯一且可排序的键对旧成员和新成员进行排序。看起来SteamID可能适用于此目的。通过两个切片迭代,通过比较键来检查添加和删除的元素。

func diff(old []*member, new []*member) {
  sort.Sort(bySteamID(old))
  sort.Sort(bySteamID(new))
  i, j := 0, 0
  for i < len(old) && j < len(new) {
    switch {
    case old[i].SteamID < new[j].SteamID:
        fmt.Println(" delete", old[i].SteamID)
        i++
    case old[i].SteamID > new[j].SteamID:
        fmt.Println(" add", new[j].SteamID)
        j++
    default:
        i++
        j++
    }
  }
  for i < len(old) {
    fmt.Println(" delete", old[i].SteamID)
    i++
  }
  for j < len(new) {
    fmt.Println(" add", new[j].SteamID)
    j++
  }
}

playground example