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.

Jason B. 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)}

Drew O. wrote:

Jason B. 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)}

Tested, and it doesn’t work, so scratch that…

Jason B. 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[x]+=1; h }.reject {
|k,v| v == 1 }

On 10/12/06, Jason B. [email protected] wrote:

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

a = [“a”, “a”, “a”, “b”, “c”, “d”, “d”]
puts a.uniq

Try it, it works!

Jason B. wrote:

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 }

Tim P. wrote:

Then I need to somehow determine that “a” appears 3 times and “d”

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”]

Jeffrey S. wrote:

Then I need to somehow determine that “a” appears 3 times and “d”
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

Jason B. wrote:

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 B. [email protected] writes:

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”]

WATANABE Hirofumi wrote:

=> [“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}]

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

appears 2 times. Any help would be great. Thanks.

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, 13 Oct 2006, Phrogz wrote:

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

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

that’s O(n^2) though… the others are O(n)

-a

On 12.10.2006 17:24, Jason B. wrote:

appears 2 times. Any help would be great. Thanks.
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