From bb2f2e5e54ad52578cfbb00c7bcf87c383d6cec1 Mon Sep 17 00:00:00 2001 From: Jonathan Gold Date: Sun, 16 Dec 2018 21:30:02 -0500 Subject: [PATCH] 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. --- util/util.go | 35 ++++++++++++++++++++++++++++++++++ util/util_test.go | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/util/util.go b/util/util.go index b031b3ba..d730fb64 100644 --- a/util/util.go +++ b/util/util.go @@ -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 +} diff --git a/util/util_test.go b/util/util_test.go index 9bd6a633..f0c745a9 100644 --- a/util/util_test.go +++ b/util/util_test.go @@ -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]) + } + } + } +}