Unique a slice of slices

Hi All,

Hope this topic is OK. If not feel free to delete :slight_smile:

I’m fairly new to Go and really just looking to learn. I’ve written some code that work (I think) but I’m interested in other approaches and constructive feedback. Especially an approach without Reflection.

Problem:

I have a slice of slices (strings) and there are multiple duplicate slices. I need to return a slice of slices which is unique and has the duplicates removed. I tried to do this without reflection but it was making my brain melt :slight_smile:

Thanks in advance for any pointers/tips/comments

(I can’t see a preview button so may edit this if the formatting is wonky
Code:

Go Playground Link

package main

import (
	"fmt"
	"reflect"
)

func main() {

	//This data will all come form an XML import, I'm just replicating the kind of data I will seee

	jb := []string{"James", "Bond"}
	mp := []string{"Mrs", "Money", "Penny"}
	xp := []string{"Mr", "Q"}

	// This is data already in the target unique slice that should remain
	us := []string{"Im", "unique", "leave", "me", "here"}

	// Create our slice of slices. With lots of duplicates that we want to remove.
	duplicateSlices := [][]string{jb, mp, mp, jb, mp, jb, mp, jb, xp, xp, xp, jb, mp}

	// This slice should contain the unique entries, plus the original value
	uniqueSlices := [][]string{us}

	for x := range duplicateSlices {
		match := false
		for y := range uniqueSlices {

			if (reflect.DeepEqual(duplicateSlices[x], uniqueSlices[y])) == false {
				match = false
			} else {
				match = true
				break
			}
		}
		if match == false {
			uniqueSlices = append(uniqueSlices, duplicateSlices[x])
		}
	}
	fmt.Println(uniqueSlices)

}

Hi, @joe19, are you asking if your use of reflect.DeepEqual can be removed so that you don’t need reflection? If so and you’re only dealing with []string slices, then you could do this:

func stringsEqual(a, b []string) bool {
    if len(a) != len(b) {
        return false
    }
    for i, x := range a {
        if x != b[i] {
            return false
        }
    }
    return true
}

I’d also like to say that your loop can be simplified:

		exists := false
		for y := range uniqueSlices {
			exists = reflect.DeepEqual(duplicateSlices[x], uniqueSlices[y])
			if exists {
				break
			}
		}
		if !exists {
			uniqueSlices = append(uniqueSlices, duplicateSlices[x])
		}
	}
1 Like

Thanks Sean, that makes a lot of sense! I didn’t consider farming out the ‘are two strings equal’ to a function. So I was trying to accomplish everything in one block of code and getting confused.

Thanks also for the loop tip :slight_smile: