util: Add PathSlice type that satisfies sort.Interface

This commit adds a []string{} type alias named PathSlice, and the
Len(), Swap(), and Less() methods required to satisfy sort.Interface.
Now you can do `sort.Sort(util.PathSlice(foo))` where foo is a slice
of paths. It will be sorted by depth in alphabetical order.
This commit is contained in:
Jonathan Gold
2018-12-16 21:30:02 -05:00
parent b1eb6711b7
commit bb2f2e5e54
2 changed files with 83 additions and 0 deletions

View File

@@ -420,3 +420,38 @@ func SortedStrSliceCompare(a, b []string) error {
}
return nil
}
// PathSlice is a type used to implement sort.Interface on a slice of strings,
// where each string is a path. This allows you to call sort.Sort() on a list
// of paths, after casting the []string{} to this type. Paths will be sorted
// by depth in alphabetical order.
type PathSlice []string
// Len returns the length of obj. It is required to satisfy sort.Interface.
func (obj PathSlice) Len() int {
return len(obj)
}
// Swap swaps obj[i] and obj[j]. it is required to satisfy sort.Interface.
func (obj PathSlice) Swap(i, j int) {
obj[i], obj[j] = obj[j], obj[i]
}
// Less returns whether obj[i] is less than obj[j]. It performs the logic
// required to satisfy sort.Interface.
func (obj PathSlice) Less(i, j int) bool {
x := PathSplitFullReversed(obj[i])
y := PathSplitFullReversed(obj[j])
if x[0] != y[0] {
return x[0] < y[0]
}
if len(x) > len(y) {
return false
}
for i := range x {
if x[i] > y[i] {
return false
}
}
return true
}

View File

@@ -857,3 +857,51 @@ func TestSortedStrSliceCompare3(t *testing.T) {
t.Errorf("input slice reordered to: %v", slice1)
}
}
func TestPathSliceSort(t *testing.T) {
tests := []struct {
in []string
out []string
}{
{
in: []string{
"/foo/bar/baz",
"/bing/bang/boom",
"/1/2/3/",
"/foo/bar/raz",
"/bing/buzz/",
"/foo/",
"/",
"/1/",
"/foo/bar/baz/bam",
"/bing/bang/",
"/1/2/",
"/foo/bar/",
"/bing/",
},
out: []string{
"/",
"/1/",
"/1/2/",
"/1/2/3/",
"/bing/",
"/bing/bang/",
"/bing/bang/boom",
"/bing/buzz/",
"/foo/",
"/foo/bar/",
"/foo/bar/baz",
"/foo/bar/baz/bam",
"/foo/bar/raz",
},
},
}
for _, tt := range tests {
sort.Sort(PathSlice(tt.in))
for i := range tt.in {
if tt.in[i] != tt.out[i] {
t.Errorf("path sort failed: wanted: %s got: %s", tt.out[i], tt.in[i])
}
}
}
}