You're currently iterating over the slice each once, and then again for each value. That's understandable, but not ideal. Why not simply sort the data, and then check whether or not the next value is the same as the current one?
func distinct(values []string) int {
if len(values) == 0 {
return 0
}
// the loop doesn't count the last value
// add if the slice isn't empty
distinct := 1
// sort the values
sort.Strings(values)
// stop iterating at the next to last element
for i := 0; i < len(values)-1; i++ {
// if the current value is distinct from the next, this is a unique word
if values[i] != values[i+1] {
distinct++
}
}
return distinct
}
Other, more general comments on your code:
- Variables like
is_discrete
is not in line with golang's coding conventions. Golang prefers camelCased
variable names. isDiscrete
.
- Your nested
if
checking i != j
and then xi == xj
can, and should be combined: if i != j && xi == xj
- Personally, I'd probably use the indexes, and just use
for i := range x
and for j := range x
.
Although it doesn't make the code perform any better, it does get rid of that rather clunky looking if isDiscrete
, you could use either one of the following snippets:
for i := range x {
inc := 1
for j := range x {
for i != j && x[i] == x[j] {
inc = 0
break
}
}
discrete += inc
}
You could also increment discrete
beforehand, and just replace inc = 0
with discrete--
in the inner loop.
While we're on the subjects of other approaches, while not efficient, it is a very easy approach:
func Discrete(vals []string) int {
unique := map[string]struct{}{}
for i := range vals {
unique[vals[i]] = struct{}{}
}
return len(unique)
}
In this code, any duplicate string value is just reassigning the same key in the map. At the end, getting the length of the map will give you the total of unique string values. Maps cause memory allocations, so it's not the most efficient way, but it's a solid way to test your code. You can pass some data to your function, and use a map to calculate what the return for any given slice of strings should be.
Last thoughts on efficiency: the golang toolchain packs a couple of really handy tools that will help you determine which approach is more efficient (writing benchmarks). If memory consumption is a worry, you can use pprof
. Not just to determine how much memory any given piece of code uses, but also which part of the code is the most likely bottleneck.