2011-08-24 59 views
2

比方说,有是一个字符串数组的数组:红宝石:以独特的子阵列相对于一个特定领域

array = [["John","Apples"],["Tim","Apples"],["Frank","Apples"], 
    ["Tom","Pears"],["John","Pears"],["Frank","Oranges"],["Tim","Oranges"]] 

现在的游戏是要选择那些对数组的第二独特价值的任何记录以一种简单的方式,例如结果可能是:

array2 = [["Frank","Apples"],["Tom","Pears"],["Tim","Oranges"]] 

有没有人知道是否有这样的单线程?

+2

我喜欢这个游戏。发布了很多聪明的答案。 –

回答

6

Array#uniq可以采取块参数:

array.uniq { |e| e[1] } 

例如:

>> array = [["John","Apples"], ["Tim","Apples"], ["Frank","Apples"], ["Tom","Pears"], ["John","Pears"], ["Frank","Oranges"], ["Tim","Oranges"]] 
>> array.uniq { |e| e[1] } 
=> [["John", "Apples"], ["Tom", "Pears"], ["Frank", "Oranges"]] 

你可能会率先拿到赛(而不是最后一次为你“可以是”输出),但我不认为有任何保证哪个一个会被选中。

注意,在1.9这个唯一的作品,1.8不喜欢它,所以你必须在1.8更加努力地工作,但不是更难:

array.inject({ }) { |h,e| h[e[1]] = e[0]; h }.map { |k,v| [ v, k ] } 

inject/map版本的工作原理相同的1.8和1.9。此外,这一个挑选最后的重复值。

+1

注意:不能在红宝石中工作1.8 –

+1

@nash:谢谢,我会添加一个免责声明。几个月后我没有碰到1.8。 –

3

在Ruby 1.8:

array.map{ |k,v| v }.uniq.map{ |uv| array.select{ |k,v| v == uv }.last } 

Hash[*array.map{ |k,v| [v,k] }.flatten].map{ |k,v| [v,k] } 

[更新: “万亩太短” 给了一个很好的答案为Ruby 1.9,上面的答案我给了有利于红宝石1.8]

+0

+1对1.8的解决方案。 –

5

另一种解决方案应该在1.8和1.9工作:

array.group_by(&:last).map { |k,v| v.last } 
# => [["John", "Pears"], ["Frank", "Apples"], ["Tim", "Oranges"]] 
+0

我有'group_by'的盲点,我一直忘记它存在。 –

+2

@mu太短了:我真的很喜欢这种方法,我已经多次派上用场了:-) –

+0

出于某种原因,我一直认为“group_by”是一种有效的支持方法,所以在编写普通的ruby时我从未使用它。去搞清楚。 –

3

facets宝石器具(除一个巨大的其他有用的方法量)的uniq_by方法:

module Enumerable 
    def uniq_by #:yield: 
    h = {}; inject([]) {|a,x| h[yield(x)] ||= a << x} 
    end 
end