I have a slice of slices of strings, and want to sort them by their frequency, I tried to follow the byAge example from the docs here http://golang.org/pkg/sort/ but was unable how to pass a list of frequencies to it.
Meaning, the outcome of the example would be:
[[a,b] [a,b,c,d] [a,c,d,e]]
Would the approach be to have "a" be represented by a custom struct with frequency as it's own attribute? That seems to be more in line with the byAge example.
func main() {
transactions := [][]string{{"a", "b"}, {"b", "c", "d", "a"}, {"c", "d", "e", "a"}}
frequencies := map[string]int{
"a": 3,
"b": 2,
"c": 2,
"d": 2,
"e": 1,
}
fmt.Println(transactions, frequencies)
}
In case you need more than the data you want to sort in the sorting process, a common way is to implement your own struct, yes. In your case this would be something like this (on play):
type SortableTransaction struct {
data []string
frequencies map[string]int
}
data
would be the slice with strings and frequencies
your specific frequency table.
The following implementation could be used for the Sort
interface:
func (s SortableTransaction) Len() int { return len(s.data) }
func (s SortableTransaction) Less(i, j int) bool {
return s.frequencies[s.data[i]] > s.frequencies[s.data[j]]
}
func (s SortableTransaction) Swap(i, j int) {
s.data[j], s.data[i] = s.data[i], s.data[j]
}
If your frequency table is constant, you can declare it at package level of course.
In case you want to sort the outer slice as well, you'd have to sort the inner slices first and then the outer slices.
For example,
package main
import (
"fmt"
"sort"
)
type NameFrequency struct {
Name string
Frequency int
}
func (nf NameFrequency) String() string {
return fmt.Sprintf("%s: %d", nf.Name, nf.Frequency)
}
type ByFrequency []NameFrequency
func (nf ByFrequency) Len() int { return len(nf) }
func (nf ByFrequency) Swap(i, j int) { nf[i], nf[j] = nf[j], nf[i] }
func (nf ByFrequency) Less(i, j int) bool {
less := nf[i].Frequency > nf[j].Frequency
if nf[i].Frequency == nf[j].Frequency {
less = nf[i].Name < nf[j].Name
}
return less
}
func SortByFrequency(names []string, frequencies map[string]int) []string {
nf := make(ByFrequency, len(names))
for i, name := range names {
nf[i] = NameFrequency{name, frequencies[name]}
}
sort.Sort(ByFrequency(nf))
sortedNames := make([]string, len(names))
for i, nf := range nf {
sortedNames[i] = nf.Name
}
return sortedNames
}
func main() {
transactions := [][]string{{"a", "b"}, {"b", "c", "d", "a"}, {"c", "d", "e", "a"}}
fmt.Println(transactions)
frequencies := map[string]int{
"a": 3,
"b": 2,
"c": 2,
"d": 2,
"e": 1,
}
fmt.Println(frequencies)
sortedTransactions := make([][]string, len(transactions))
for i, transaction := range transactions {
sortedTransactions[i] = SortByFrequency(transaction, frequencies)
}
fmt.Println(sortedTransactions)
}
Output:
[[a b] [b c d a] [c d e a]]
map[a:3 b:2 c:2 d:2 e:1]
[[a b] [a b c d] [a c d e]]