[go-nuts] diff of two slices

3,914 views
Skip to first unread message

Peter Allen

unread,
May 21, 2010, 7:25:32 PM5/21/10
to golang-nuts
I'm having trouble trying to wrap my head around this...

I have two, unsorted, slices of strings and need to write a func that
will return the difference between the two. Something like this:

func diffSlice (firstSlice []string, secondSlice []string) []string {

I'd like it to return a slice that only contains the strings NOT
present in both slices. I can do this pretty easily in perl using
hashes, but need a way to do it in go.

# Diff an array in perl
sub diff_array {
my $first = $_[0]; # A reference to the first array
my $second = $_[1]; # A reference to the second array
my @diff; # The diff of the two arrays
my %count; # A hash to count the occurance of
each value

foreach my $value (@$first, @$second) {
$count{$value}++;
}

foreach my $value (keys %count) {
if ($count{$value} < 2) {
push(@diff, $value);
}
}

return(@diff);
}

roger peppe

unread,
May 21, 2010, 7:35:59 PM5/21/10
to Peter Allen, golang-nuts
something like this perhaps?

import "container/vector"

func Diff(a, b []string) []string {
m := make(map[string]bool)
for _, s := range a {
m[s] = true
}
var v vector.StringVector
for _, s := range b {
if !m[s] {
v.Push(s)
}
}
return ([]string)(v)

Kevin Ballard

unread,
May 21, 2010, 7:36:57 PM5/21/10
to Peter Allen, golang-nuts
It seems pretty straightforward to port your Perl to Go.

import (
"container/vector"
)

func diff_array(first, second []string) []string {
count := make(map[string]int)
for _, ary := range [][]string{first, second} {
for _, elem := range ary {
count[elem]++
}
}
var result vector.StringVector
for k, v := range count {
if v < 2 {
result.Push(k)
}
}
return result.Data()
--
Kevin Ballard
http://kevin.sb.org
kbal...@gmail.com

Kevin Ballard

unread,
May 21, 2010, 7:40:01 PM5/21/10
to roger peppe, Peter Allen, golang-nuts
This returns b - a, but the original poster seemed to be asking for
the a ⋃ b - a ⋂ b.

-Kevin Ballard

roger peppe

unread,
May 21, 2010, 7:46:54 PM5/21/10
to Kevin Ballard, Peter Allen, golang-nuts
On 22 May 2010 00:40, Kevin Ballard <kbal...@gmail.com> wrote:
> This returns b - a, but the original poster seemed to be asking for
> the a ⋃ b - a ⋂ b.

you're absolutely right - i even tested it and ignored the result
that i wasn't expecting!

this is better, i think, and doesn't have the original perl's bug
that it can get it wrong if there are duplicates in either slice:

func Diff(a, b []string) []string {
m := make(map[string]bool)
for _, s := range a {
m[s] = true
}
var v vector.StringVector
for _, s := range b {
if !m[s] {
v.Push(s)
}else{
m[s] = false, false
}
}
for s, _ := range m {
v.Push(s)
}
return ([]string)(v)
}

Peter Allen

unread,
May 24, 2010, 1:19:54 PM5/24/10
to golang-nuts
Thanks! This does exactly what I wanted. Looks like vectors are
definitely what I need to be using to dynamically size my lists.
> kball...@gmail.com

Peter Allen

unread,
May 24, 2010, 7:53:01 PM5/24/10
to golang-nuts
Just a quick note... this was throwing exceptions for me, I believe
because you can't increment a map element that doesn't already exist.
Here's the solution I went with, which also returns the size of the
new slice (FYI, it's ok if I throw away duplicate strings, even if
they manage to show up twice in one slice but zero in the other).

func diffSlice (first, second []string) ([]string, int) {
count := make(map[string]int);
for _, x := range first {
_, present := count[x];
if !present {
count[x] = 0;
}
count[x]++;
}
for _, x := range second {
_, present := count[x];
if !present {
count[x] = 0;
}
count[x]++;
}
var result vector.StringVector;
for k, v := range count {
if v < 2 {
result.Push(k);
}
}
return result.Data(), len(result.Data());
}

On May 21, 4:36 pm, Kevin Ballard <kball...@gmail.com> wrote:
> It seems pretty straightforward to port your Perl to Go.
>
> import (
>     "container/vector"
> )
>
> func diff_array(first, second []string) []string {
>     count := make(map[string]int)
>     for _, ary := range [][]string{first, second} {
>         for _, elem := range ary {
>             count[elem]++
>         }
>     }
>     var result vector.StringVector
>     for k, v := range count {
>         if v < 2 {
>             result.Push(k)
>         }
>     }
>     return result.Data()
>
>
>
>
>
> }
> On Fri, May 21, 2010 at 4:25 PM, Peter Allen <pacdra...@gmail.com> wrote:
> > I'm having trouble trying to wrap my head around this...
>
> > I have two, unsorted, slices of strings and need to write a func that
> > will return the difference between the two. Something like this:
>
> > func diffSlice (firstSlice []string, secondSlice []string) []string {
>
> > I'd like it to return aslicethat only contains the strings NOT
> > present in both slices. I can do this pretty easily in perl using
> > hashes, but need a way to do it in go.
>
> > #Diffan array in perl
> > sub diff_array {
> >        my $first = $_[0];      # A reference to the first array
> >        my $second = $_[1];     # A reference to the second array
> >        my @diff;               # Thediffof the two arrays
> >        my %count;              # A hash to count the occurance of
> > each value
>
> >        foreach my $value (@$first, @$second) {
> >                $count{$value}++;
> >        }
>
> >        foreach my $value (keys %count) {
> >                if ($count{$value} < 2) {
> >                        push(@diff, $value);
> >                }
> >        }
>
> >        return(@diff);
> > }
>
> --
> Kevin Ballardhttp://kevin.sb.org
> kball...@gmail.com

Kevin Ballard

unread,
May 24, 2010, 7:55:51 PM5/24/10
to Peter Allen, golang-nuts
The code worked fine for me. Have you updated your version of go
lately? There was a change a while back to make maps return the zero
element if you access a key which is not present.

-Kevin Ballard

Peter Allen

unread,
May 24, 2010, 8:07:09 PM5/24/10
to golang-nuts
Ah, that must be it, I haven't updated in months. Thanks!

On May 24, 4:55 pm, Kevin Ballard <kball...@gmail.com> wrote:
> The code worked fine for me. Have you updated your version of go
> lately? There was a change a while back to make maps return the zero
> element if you access a key which is not present.
>
> -Kevin Ballard
>
>
>
>
>
> On Mon, May 24, 2010 at 4:53 PM, Peter Allen <pacdra...@gmail.com> wrote:
> > Just a quick note... this was throwing exceptions for me, I believe
> > because you can't increment a map element that doesn't already exist.
> > Here's the solution I went with, which also returns the size of the
> > newslice(FYI, it's ok if I throw away duplicate strings, even if
> > they manage to show up twice in oneslicebut zero in the other).
> kball...@gmail.com
Reply all
Reply to author
Forward
0 new messages