I am also new to Go, and I guess, we have the same Book :) I did it like this: func RemoveAdjacentDuplicates(strings []string) []string { if len(strings) < 2 { return strings } current, nextDifferent := 0, 1 for nextDifferent < len(strings) { for nextDifferent < len(strings) && strings[current] == strings[nextDifferent] { nextDifferent++ } if nextDifferent < len(strings) { if current+1 != nextDifferent { strings[current+1] = strings[nextDifferent] } strings[current+1] = strings[nextDifferent] current++ } } return strings[:current+1] } The advantage is, that you will not copy the whole tail of the slice several times when there are several ranges of duplicates. I am aware, that this also is not the best solution. One could copy whole ranges of unique strings at once instead of copy them one by one, which may be even more efficient. And here a maybe more efficient one with comments, which copies in chunks with `copy` A lot of code for a simple task. I don't know if it is really more performant as simpler solutions (regarding code) and I am sure that it can be done easier. func RemoveAdjacentDuplicates(strings []string) []string { // at least two elements need to be in the slice to have adjacent duplicates if len(strings) < 2 { return strings } current, nextDifferent, nextDifferentEnd := 0, 1, 0 for nextDifferentEnd+1 < len(strings) { // search for next different element for nextDifferent < len(strings) && strings[current] == strings[nextDifferent] { nextDifferent++ } // look for the largest subslice from the next different up to the next duplicate nextDifferentEnd = nextDifferent + 1 for nextDifferentEnd < len(strings) && strings[nextDifferentEnd-1] != strings[nextDifferentEnd] { nextDifferentEnd++ } // if we did not reach the and of the slice, // replace the duplicate(s) with the next subslice with different elements if nextDifferent < len(strings) { if current+1 != nextDifferent { copy(strings[current+1:], strings[nextDifferent:nextDifferentEnd]) } current += nextDifferentEnd - nextDifferent nextDifferent = nextDifferentEnd } } // finally, current will index the last element of the result slice return strings[:current+1] } Or, how about this one? func FirstSubsliceWithoutAdjacentDuplicates(strings []string) ([]string, int) { if len(strings) < 2 { return strings, 0 } for i := 1; i < len(strings); i++ { if strings[i-1] == strings[i] { repeats := 1 for i+repeats < len(strings) && strings[i] == strings[i+repeats] { repeats++ } return strings[:i], repeats } } return strings, 0 } func RemoveAdjacentDuplicates(toBeProcessed []string) []string { unique, repeats := FirstSubsliceWithoutAdjacentDuplicates(toBeProcessed) if len(unique) == len(toBeProcessed) { return unique } result := toBeProcessed copyTarget := toBeProcessed finalLength := 0 for len(unique) > 0 { finalLength += len(unique) copy(copyTarget, unique) toBeProcessed = toBeProcessed[len(unique)+repeats:] copyTarget = copyTarget[len(unique):] unique, repeats = FirstSubsliceWithoutAdjacentDuplicates(toBeProcessed) } return result[0:finalLength] }