我想知道是否有可能在使用索引找出使用相同id的结构的切片范围中的位置时进行组排序。
所以本质上我有这段代码:
package main
import (
"fmt"
"sort"
)
type (
Column struct {
ID string
Name string
}
ByIDAndIndex []Column
)
func (c ByIDAndIndex) Len() int { return len(c) }
func (c ByIDAndIndex) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c ByIDAndIndex) Less(i, j int) bool {
if c[i].ID == c[j].ID {
return i > j
}
return i < j
}
func main() {
columns := []Column{
Column{
"1",
"Red Apple",
},
Column{
"1",
"Yellow Apple",
},
Column{
"1",
"Bismarck Apple",
},
Column{
"2",
"Orange",
},
Column{
"1",
"Anna Apple",
},
}
sort.Sort(ByIDAndIndex(columns))
for _, c := range columns {
fmt.Println(c.ID, c.Name)
}
}
哪个输出:
1 Bismarck Apple
1 Yellow Apple
1 Red Apple
2 Orange
1 Anna Apple
但是我希望它输出:
1 Bismarck Apple
1 Yellow Apple
1 Red Apple
1 Anna Apple
2 Orange
由于“安娜苹果”是相同的ID。它仍然保持最后的位置,带有其他相同的ID。我想解决这个问题的一种方法是简单地编写自己的分配新切片的排序函数。遍历提供的片,追加第一项,查找具有相同ID的其他任何项,然后将其追加到新片中。转到提供的下一项,检查该ID是否已添加,然后重复。
我不确定提供的Sort接口是否有效,因为它似乎在真正完成之前就退出了。
是,有可能,但是less()
函数必须判断一个元素是否小于另一个元素。
如果您主要想按ID
进行排序,则ID不相等时必须返回c[i].ID < c[j].ID
。
例如:
func (c ByIDAndIndex) Less(i, j int) bool {
if c[i].ID != c[j].ID {
return c[i].ID < c[j].ID
}
return i > j
}
还要注意,使用传递的索引进行进一步的比较并不是相等ID之间的确定顺序,它取决于实际的排序实现/算法。因此,以上可能导致顺序不同,它只能保证ID不同的正确排序。
您应该使用稳定的排序。同样,由于要对切片进行排序,因此可以使用sort.SliceStable()
,因此只需提供sort.SliceStable()
功能。稳定的排序保证了“相等”的元素不会相互切换/重新排序。
less()
这将输出(在type Column struct {
ID string
Name string
}
func main() {
columns := []Column{
// ...
}
sort.SliceStable(columns, func(i, j int) bool {
return columns[i].ID < columns[j].ID
})
for _, c := range columns {
fmt.Println(c.ID, c.Name)
}
}
上尝试):
Go Playground
如果不需要稳定排序,并且您真的想在ID相同时根据原始索引决定顺序,则必须先存储索引,然后再对它们进行排序,因为排序算法会重新排列项目和原始索引索引将不再可用,并且同一元素的索引在排序操作期间可能会多次更改。