Forum: Ruby Returning a duplicate from an Array

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Jeff M. (Guest)
on 2009-01-14 00:01
Hey guys,
 I have an array of names that may contain duplicates. What I would like
to do is return an array OF THE DUPLICATES. I was looking around at
various built-in methods for arrays, but the closest thing I can find is
Array.uniq, which returns the array without the duplicates.

Any suggestions on how to do this?

Thanks,
 - Jeff M.
Andy C. (Guest)
on 2009-01-14 00:06
(Received via mailing list)
> Thanks,
>  - Jeff M.
> --

Without really looking into it a quick and dirty way would be to just
subtract the results of .uniq from the initial array.

Andy C..
Jeff M. (Guest)
on 2009-01-14 00:19
Andy C. wrote:
>
> Without really looking into it a quick and dirty way would be to just
> subtract the results of .uniq from the initial array.
>
> Andy C..

Thanks for the quick reply! However, after trying it, I found that
subtracting an array from an array will delete each instance of an
element, leaving me with a blank array, IE:

[ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ]  #=>  [ 3, 3, 5 ]

Any other ideas?

Thanks again,
 - Jeff M.
Andy C. (Guest)
on 2009-01-14 00:20
(Received via mailing list)
> > Thanks,
> >  - Jeff M.
> > --
>
> Without really looking into it a quick and dirty way would be to just
> subtract the results of .uniq from the initial array.
>
> Andy C..

Nevermind that wont work afterall, wasn't thinking about how arrays work
at the time.

  def dups(ary=[])
    uniq=ary.uniq
    ary.reject{|z| if(uniq.include?(z));q-=[z];true;end}
  end

There that should do the trick.  Still very probably not the best of
ways to do it though.

Andy C..
Andy C. (Guest)
on 2009-01-14 00:32
(Received via mailing list)
> element, leaving me with a blank array, IE:
>
> [ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ]  #=>  [ 3, 3, 5 ]
>
> Any other ideas?
>
> Thanks again,
>  - Jeff M.
> --

Yeah, I am winning the typing contest today.

>   def dups(ary=[])
>     uniq=ary.uniq
>     ary.reject{|z| if(uniq.include?(z));q-=[z];true;end}
>   end

Should actually be

   def dups(ary=[])
     uniq=ary.uniq
     ary.reject{|z| if(uniq.include?(z));uniq-=[z];true;end}
   end

Made a mistake when I made q make more sense aparently.

Andy C.
Jeff M. (Guest)
on 2009-01-14 00:41
Thanks! That works great.

I appreciate the help!
 - Jeff M.
Brian C. (Guest)
on 2009-01-14 11:48
This version does only a single pass through the array:

  def dups(ary)
    seen = {}
    ary.find_all { |x| seen[x] || (seen[x]=true; false) }
  end

  p dups([1,2,3,1,4,5,6,3])
Pierre P. (Guest)
on 2009-01-15 04:36
I'd do like this:
a.select{|x| a.index(x) != a.rindex(x)}.uniq

Now, I wouldn't know which one is more efficient, but coding wise, I
like that way :-)
Jimmy K. (Guest)
on 2009-01-15 13:19
> Pierre P. wrote:
> I'd do like this:
> a.select{|x| a.index(x) != a.rindex(x)}.uniq
>
> Now, I wouldn't know which one is more efficient, but coding wise, I
> like that way :-)

Here's yet another take on it:

class Array
   def dups
      uniq.select{ |e| (self-[e]).size < self.size - 1 }
   end
end

p [ 1, 1, 2, 2, 3, 3, 4, 5 ].dups   #=> [1, 2, 3]

see: http://snippets.dzone.com/posts/show/4148

Cheers,

j.k.
Tiago N. (Guest)
on 2009-01-15 13:44
(Received via mailing list)
Jimmy K. escreveu:
> class Array
>
> j.k.
>
I Think that the way :

class Array
   def dups
      uniq.select{ |e| (self-[e]).size < self.size - 1 }
   end
end
p [ 1, 1, 2, 2, 3, 3, 4, 5 ].dups   #=> [1, 2, 3]


is more elegant!

tiago
Klaus S. (Guest)
on 2009-01-15 14:11
(Received via mailing list)
Pierre P. <removed_email_address@domain.invalid> wrote:
> I'd do like this:
> a.select{|x| a.index(x) != a.rindex(x)}.uniq
>
> Now, I wouldn't know which one is more efficient, but coding wise, I
> like that way :-)
>
If order is not important:
h = Hash.new(0)
a.each { |x| h[x]+=1 }
h.select {|k,v| v>1 }.keys

should be O(n) and with only one iteration through a.

Klaus
--
http://lapiz.istik.de/

The Answer is 42. And I am the Answer. Now I am looking for the
Question.
Jesús Gabriel y Galán (Guest)
on 2009-01-15 14:24
(Received via mailing list)
On Thu, Jan 15, 2009 at 12:18 PM, Jimmy K.
<removed_email_address@domain.invalid> wrote:
>
> class Array
>   def dups
>      uniq.select{ |e| (self-[e]).size < self.size - 1 }
>   end
> end
>
> p [ 1, 1, 2, 2, 3, 3, 4, 5 ].dups   #=> [1, 2, 3]

Regarding this and other solutions: the OP accepted a solution from
Andy C. which return *all* duplicates.
I mean, if a number appears three times, it will appear two in the
solution, and not one:

irb(main):001:0> a = [1,1,1,1,2,2,3,4,5,5,5]
=> [1, 1, 1, 1, 2, 2, 3, 4, 5, 5, 5]
irb(main):008:0> class Array
irb(main):009:1>   def dups
irb(main):010:2>      uniq.select{ |e| (self-[e]).size < self.size - 1 }
irb(main):011:2>   end
irb(main):012:1> end
=> nil
irb(main):013:0> a.dups
=> [1, 2, 5]

Should be [1,1,1,2,3,4,5,5]. If order is not important:

irb(main):014:0> class Array
irb(main):015:1> def dups
irb(main):016:2> h = Hash.new 0
irb(main):017:2> each {|x| h[x] += 1}
irb(main):018:2> h.inject([]) {|res, (k,v)| res << ([k] * (v-1)) if v
> 1; res.flatten}
irb(main):019:2> end
irb(main):020:1> end
=> nil
irb(main):021:0> a.dups
=> [5, 5, 1, 1, 1, 2]

Jesus.
This topic is locked and can not be replied to.