The best selling products this week
The weekly email lists the top products by units sold. Sales come in one row per transaction, so the same product appears many times.
- Add up the units per product name first.
- Order by units sold, largest first; products level on units go alphabetically.
- Return at most `howMany` names, or fewer if there are not that many products.
- Asking for zero or fewer returns nothing.
topSellers(sales: list<Sale>, howMany: int) → list<string>
Go needs a compiler and Drill does not host one yet, so this page is the reference rather than an exercise: the problem, worked examples, and the solution in full. To type it out, the same problem runs in Python.
Where you start
func topSellers(sales []Sale, howMany int) []string {
}
Worked examples
| Call | Result |
|---|---|
topSellers([]Sale{Sale{Name: "mug", Qty: 5}, Sale{Name: "pen", Qty: 3}, Sale{Name: "mug", Qty: 2}}, 2) | []string{"mug", "pen"} |
topSellers([]Sale{Sale{Name: "zip", Qty: 1}, Sale{Name: "ace", Qty: 1}}, 2) | []string{"ace", "zip"} |
topSellers([]Sale{Sale{Name: "mug", Qty: 5}, Sale{Name: "pen", Qty: 9}}, 1) | []string{"pen"} |
topSellers([]Sale{Sale{Name: "mug", Qty: 5}}, 0) | []string{} |
Hint
Aggregate into a map, then sort the entries. The tie-break is what most solutions forget.
Reference solution in Go
func topSellers(sales []Sale, howMany int) []string {
totals := map[string]int{}
names := []string{}
for _, s := range sales {
if _, ok := totals[s.Name]; !ok {
names = append(names, s.Name)
}
totals[s.Name] += s.Qty
}
sort.Slice(names, func(i, j int) bool {
if totals[names[i]] != totals[names[j]] {
return totals[names[i]] > totals[names[j]]
}
return names[i] < names[j]
})
if howMany <= 0 {
return []string{}
}
if howMany < len(names) {
names = names[:howMany]
}
return names
}