jasonb
October 12, 2006, 5:24pm
1
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.
jasonb
October 12, 2006, 6:02pm
2
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)}
jasonb
October 12, 2006, 6:05pm
3
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)}
jasonb
October 12, 2006, 6:28pm
4
Tested, and it doesn’t work, so scratch that…
jasonb
October 12, 2006, 8:42pm
5
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 }
jasonb
October 18, 2006, 10:38am
6
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
jasonb
October 12, 2006, 9:16pm
7
a = [“a”, “a”, “a”, “b”, “c”, “d”, “d”]
puts a.uniq
Try it, it works!
jasonb
October 18, 2006, 10:38am
8
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 }
jasonb
October 18, 2006, 10:38am
9
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”]
jasonb
October 18, 2006, 10:38am
10
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
jasonb
October 18, 2006, 10:38am
11
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.
jasonb
October 18, 2006, 10:38am
12
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”]
jasonb
October 18, 2006, 10:39am
13
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}]
jasonb
October 18, 2006, 10:38am
14
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…
jasonb
October 18, 2006, 10:39am
15
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
jasonb
October 18, 2006, 10:40am
16
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