Isolating non-unique items in an array

I'm basically trying to the opposite of .uniq Let's say I have an array:

["a", "a", "a", "b", "c", "d", "d"]

I would like to boil this down by first tossing the values that only
appear once. Which leaves me with:

["a", "a", "a", "d", "d"]

Then I need to somehow determine that "a" appears 3 times and "d"
appears 2 times. Any help would be great. Thanks.

···

--
Posted via http://www.ruby-forum.com/.

class Array
  def count( item )
    return 0 unless self.include? item

    c = 0
    self.each {|i| c += 1 if i == item}
    return c
  end
end

ary = %w(a a a b c d d)
new_ary = ary.select {|item| ary.count(item) > 1}

counts = Hash.new {|h,k| h[k] = new_ary.count(k)}

It's not going to be fast, but it should work.

Blessings,
TwP

···

On 10/12/06, Jason Burgett <jasbur@gmail.com> wrote:

I'm basically trying to the opposite of .uniq Let's say I have an array:

["a", "a", "a", "b", "c", "d", "d"]

I would like to boil this down by first tossing the values that only
appear once. Which leaves me with:

["a", "a", "a", "d", "d"]

Then I need to somehow determine that "a" appears 3 times and "d"
appears 2 times. Any help would be great. Thanks.

--
Posted via http://www.ruby-forum.com/\.

Jason Burgett wrote:

I'm basically trying to the opposite of .uniq Let's say I have an array:

["a", "a", "a", "b", "c", "d", "d"]

I would like to boil this down by first tossing the values that only appear once. Which leaves me with:

["a", "a", "a", "d", "d"]

Then I need to somehow determine that "a" appears 3 times and "d" appears 2 times. Any help would be great. Thanks.

# Output:
# ["a", "a", "a", "d", "d"]
# {"a"=>3, "d"=>2}

def get_counts(keys)
     counts = Hash.new(0)
     keys.each {|k| counts[k] += 1 }
     counts
end

def non_uniq(elements)
     counts = get_counts(elements)
     counts.delete_if {|k, v| v < 2 }
     elements.select {|e| counts.key?(e) }
end

elements = ["a", "a", "a", "b", "c", "d", "d"]

p non_uniq(elements)
p get_counts(elements).delete_if {|k, v| v < 2 }

Jason Burgett wrote:

I'm basically trying to the opposite of .uniq Let's say I have an array:

["a", "a", "a", "b", "c", "d", "d"]

I would like to boil this down by first tossing the values that only
appear once. Which leaves me with:

["a", "a", "a", "d", "d"]

Then I need to somehow determine that "a" appears 3 times and "d"
appears 2 times. Any help would be great. Thanks

This should work:

a = ["a", "a", "a", "b", "c", "d", "d"]
a.uniq.map{|i| i if (a.map{|j| j if j==i}.length > 1)}

···

--
Posted via http://www.ruby-forum.com/\.

There are bound to be better ways, but you could try something like:

a = ["a", "a", "a", "b", "c", "d", "d"]
# => ["a", "a", "a", "b", "c", "d", "d"]

hsh = a.inject(Hash.new{|h,k| h[k] = 0}) {|h,v| h[v] += 1 ; h}.reject!
{|k,v| v == 1}
# => {"a"=>3, "d"=>2}

hsh['a']
# => 3
hsh['d']
# => 2

Depending on how you're using the results, You could also run a second
inject to reverse the lookup:

rhsh = hsh.inject(Hash.new { |h,k| h[k] = }) { |h,(k,v)| h[v] << k ;
h }
# => {2=>["d"], 3=>["a"]}

(2..rhsh.keys.max).each { |i| puts "count #{i}: #{rhsh[i]}" }
# count 2: d
# count 3: a

If you went with this way, I guess you could forget about getting rid of
the 1s with reject!, since you could just ignore the 1 key in the
rhsh...

···

On Fri, 2006-10-13 at 00:24 +0900, Jason Burgett wrote:

I'm basically trying to the opposite of .uniq Let's say I have an array:

["a", "a", "a", "b", "c", "d", "d"]

I would like to boil this down by first tossing the values that only
appear once. Which leaves me with:

["a", "a", "a", "d", "d"]

Then I need to somehow determine that "a" appears 3 times and "d"
appears 2 times. Any help would be great. Thanks.

--
Ross Bamford - rosco@roscopeco.REMOVE.co.uk

Jason Burgett wrote:

I'm basically trying to the opposite of .uniq Let's say I have an array:

["a", "a", "a", "b", "c", "d", "d"]

I would like to boil this down by first tossing the values that only appear once. Which leaves me with:

["a", "a", "a", "d", "d"]

Then I need to somehow determine that "a" appears 3 times and "d" appears 2 times. Any help would be great. Thanks.

Here's what I whipped up:

letters = ['a','a','a','b','c','d','d']
counts = {}

letters.each do |letter|
  count = letters.find_all { |x| x == letter }.size
  counts[letter] = count if count > 1
end

non_unique_letters = letters.find_all { |x| counts.has_key?(x) }

p counts
p non_unique_letters

Jamey

Confidentiality Notice: This email message, including any attachments, is for the sole use of the intended recipient(s) and may contain confidential and/or privileged information. If you are not the intended recipient(s), you are hereby notified that any dissemination, unauthorized review, use, disclosure or distribution of this email and any materials contained in any attachments is prohibited. If you receive this message in error, or are not the intended recipient(s), please immediately notify the sender by email and destroy all copies of the original message, including attachments.

Hi,

Jason Burgett <jasbur@gmail.com> writes:

I'm basically trying to the opposite of .uniq Let's say I have an array:

["a", "a", "a", "b", "c", "d", "d"]

I would like to boil this down by first tossing the values that only
appear once. Which leaves me with:

["a", "a", "a", "d", "d"]

Then I need to somehow determine that "a" appears 3 times and "d"
appears 2 times. Any help would be great. Thanks.

% irb

a = ["a", "a", "a", "b", "c", "d", "d"]

=> ["a", "a", "a", "b", "c", "d", "d"]

a.select{|i| a.grep(i).size > 1}

=> ["a", "a", "a", "d", "d"]

···

--
eban

Jason Burgett wrote:

I'm basically trying to the opposite of .uniq Let's say I have an array:

["a", "a", "a", "b", "c", "d", "d"]

I would like to boil this down by first tossing the values that only
appear once. Which leaves me with:

["a", "a", "a", "d", "d"]

Then I need to somehow determine that "a" appears 3 times and "d"
appears 2 times. Any help would be great. Thanks.

a = %w( a a a b c d d )
want_and_counts = a.inject( Hash.new(0) ) { |h,x| h+=1; h }.reject {

···

k,v| v == 1 }

--
Posted via http://www.ruby-forum.com/\.

Did anyone suggest inject + partition yet? If not:

irb(main):001:0> a = ["a", "a", "a", "b", "c", "d", "d"]
=> ["a", "a", "a", "b", "c", "d", "d"]
irb(main):002:0> stat = a.inject(Hash.new(0)) do |h, e|
irb(main):003:1* h[e] += 1
irb(main):004:1> h
irb(main):005:1> end
=> {"a"=>3, "b"=>1, "c"=>1, "d"=>2}
irb(main):006:0> one, multi = stat.partition {|e,c| c == 1}
=> [[["b", 1], ["c", 1]], [["a", 3], ["d", 2]]]
irb(main):007:0> one
=> [["b", 1], ["c", 1]]
irb(main):008:0> multi
=> [["a", 3], ["d", 2]]
irb(main):009:0> one.map! {|e,c| e}
=> ["b", "c"]

Kind regards

  robert

···

On 12.10.2006 17:24, Jason Burgett wrote:

I'm basically trying to the opposite of .uniq Let's say I have an array:

["a", "a", "a", "b", "c", "d", "d"]

I would like to boil this down by first tossing the values that only appear once. Which leaves me with:

["a", "a", "a", "d", "d"]

Then I need to somehow determine that "a" appears 3 times and "d" appears 2 times. Any help would be great. Thanks.

Tim Pease wrote:

I'm basically trying to the opposite of .uniq Let's say I have an array:

["a", "a", "a", "b", "c", "d", "d"]

I would like to boil this down by first tossing the values that only
appear once. Which leaves me with:

["a", "a", "a", "d", "d"]

Then I need to somehow determine that "a" appears 3 times and "d"
appears 2 times. Any help would be great. Thanks.

--
Posted via http://www.ruby-forum.com/\.

class Array
def count( item )
   return 0 unless self.include? item

   c = 0
   self.each {|i| c += 1 if i == item}
   return c
end
end

ary = %w(a a a b c d d)
new_ary = ary.select {|item| ary.count(item) > 1}

Better:

class Array
   def counts # could be golfed, but clarity is king
     result = Hash.new{0}
     self.each {|a| result[a] += 1}
     result
   end
end

a = ["a", "a", "a", "b", "c", "d", "d"]
c = a.counts
a.reject{|b| c[b] == 1} # => ["a", "a", "a", "d", "d"]

···

On 10/12/06, Jason Burgett <jasbur@gmail.com> wrote:

--
Alex

Jeffrey Schwab wrote:

Jason Burgett wrote:

I'm basically trying to the opposite of .uniq Let's say I have an array:

["a", "a", "a", "b", "c", "d", "d"]

I would like to boil this down by first tossing the values that only appear once. Which leaves me with:

["a", "a", "a", "d", "d"]

Then I need to somehow determine that "a" appears 3 times and "d" appears 2 times. Any help would be great. Thanks.

# Output:
# ["a", "a", "a", "d", "d"]
# {"a"=>3, "d"=>2}

def get_counts(keys)
    counts = Hash.new(0)
    keys.each {|k| counts[k] += 1 }
    counts
end

def non_uniq(elements)
    counts = get_counts(elements)
    counts.delete_if {|k, v| v < 2 }
    elements.select {|e| counts.key?(e) }
end

# Better:
def non_uniq(elements)
     counts = get_counts(elements)
     elements.select {|e| counts[e] > 1 }
end

···

elements = ["a", "a", "a", "b", "c", "d", "d"]

p non_uniq(elements)
p get_counts(elements).delete_if {|k, v| v < 2 }

Drew Olson wrote:

Jason Burgett wrote:

I'm basically trying to the opposite of .uniq Let's say I have an array:

["a", "a", "a", "b", "c", "d", "d"]

I would like to boil this down by first tossing the values that only
appear once. Which leaves me with:

["a", "a", "a", "d", "d"]

Then I need to somehow determine that "a" appears 3 times and "d"
appears 2 times. Any help would be great. Thanks

This should work:

a = ["a", "a", "a", "b", "c", "d", "d"]
a.uniq.map{|i| i if (a.map{|j| j if j==i}.length > 1)}

Actually, so that you have them appear more than once you'd need to do:

a = ["a", "a", "a", "b", "c", "d", "d"]
a.map{|i| i if (a.map{|j| j if j==i}.length > 1)}

···

--
Posted via http://www.ruby-forum.com/\.

Tested, and it doesn't work, so scratch that...

···

--
Posted via http://www.ruby-forum.com/.

WATANABE Hirofumi wrote:

Jason Burgett <jasbur@gmail.com> writes:
> ["a", "a", "a", "d", "d"]
>
> Then I need to somehow determine that "a" appears 3 times and "d"
> appears 2 times. Any help would be great. Thanks.

% irb
>> a = ["a", "a", "a", "b", "c", "d", "d"]
=> ["a", "a", "a", "b", "c", "d", "d"]
>> a.select{|i| a.grep(i).size > 1}
=> ["a", "a", "a", "d", "d"]

Taking that one step further to meet his second need:

class Array
  def duplicates_count
    uniq.map{ |e|
      if ( count = grep(e).size ) > 1
        { e => count }
      end
    }.compact
  end
end

a = ["a", "a", "a", "b", "c", "d", "d"]
p a.duplicates_count
#=> [{"a"=>3}, {"d"=>2}]

a = ["a", "a", "a", "b", "c", "d", "d"]
puts a.uniq

Try it, it works!

···

--
Posted via http://www.ruby-forum.com/.

that's O(n^2) though... the others are O(n)

-a

···

On Fri, 13 Oct 2006, Phrogz wrote:

WATANABE Hirofumi wrote:

Jason Burgett <jasbur@gmail.com> writes:

["a", "a", "a", "d", "d"]

Then I need to somehow determine that "a" appears 3 times and "d"
appears 2 times. Any help would be great. Thanks.

% irb

a = ["a", "a", "a", "b", "c", "d", "d"]

=> ["a", "a", "a", "b", "c", "d", "d"]

a.select{|i| a.grep(i).size > 1}

=> ["a", "a", "a", "d", "d"]

Taking that one step further to meet his second need:

class Array
def duplicates_count
   uniq.map{ |e|
     if ( count = grep(e).size ) > 1
       { e => count }
     end
   }.compact
end
end

a = ["a", "a", "a", "b", "c", "d", "d"]
p a.duplicates_count
#=> [{"a"=>3}, {"d"=>2}]

--
my religion is very simple. my religion is kindness. -- the dalai lama