【发布时间】:2009-09-02 18:28:12
【问题描述】:
我知道 ||= 运算符,但认为它在这里对我没有帮助...尝试创建一个数组来计算对象数组中“类型”的数量。
array.each do |c|
newarray[c.type] = newarray[c.type] ? newarray[c.type]+1 ? 0
end
有没有更优雅的方式来做到这一点?
【问题讨论】:
-
第二个问号应该是冒号。
我知道 ||= 运算符,但认为它在这里对我没有帮助...尝试创建一个数组来计算对象数组中“类型”的数量。
array.each do |c|
newarray[c.type] = newarray[c.type] ? newarray[c.type]+1 ? 0
end
有没有更优雅的方式来做到这一点?
【问题讨论】:
types = Hash.new(-1) # It feels like this should be 0, but to be
# equivalent to your example it needs to be -1
array.each do |c|
types[c.type] += 1
end
【讨论】:
使用Array#fetch 方法,如果索引不存在,您可以为其提供默认值:
array.each do |c|
newarray[c.type] = newarray.fetch(c.type, -1) + 1
end
【讨论】:
array.each do |c|
newarray[c.type] = 1 + (newarray[c.type] || -1)
end
或者
array.each do |c|
newarray[c.type] ||= -1
newarray[c.type] += 1
end
【讨论】:
||= 确实有帮助:
types = {}
array.each do |c|
types[c.class] ||= 0
types[c.class] += 1
end
【讨论】:
你的变量 newarray 的名字很奇怪,因为在 Ruby 和大多数其他语言中,数组是由整数索引的,而不是像 Class 这样的随机对象。这更有可能是Hash。
此外,您应该使用c.class,而不是c.type,后者已被弃用。
最后,既然您要创建Hash,您可以像这样使用inject:
newarray = array.inject( {} ) do |h,c|
h[c.class] = h.key?(c.class) ? h[c.class]+1 : 0
h
end
或者,对于单行:
newarray = array.inject( {} ) { |h,c| h[c.class] = h.key?(c.class) ? h[c.class]+1 : 0 ; h }
如您所见,这给出了预期的结果:
irb(main):001:0> array = [1, {}, 42, [], Object.new(), [1, 2, 3]]
=> [1, {}, 42, [], #<Object:0x287030>, [1, 2, 3]]
irb(main):002:0> newarray = array.inject( {} ) { |h,c| h[c.class] = h.key?(c.class) ? h[c.class]+1 : 0 ; h }
=> {Object=>0, Hash=>0, Array=>1, Fixnum=>1}
【讨论】:
在 Ruby 1.8.7 或更高版本中,您可以使用 group_by,然后将每个元素列表转换为 count - 1,并从 map 返回的数组中生成哈希。
Hash[array.group_by(&:class).map { |k,v| [k, v.size-1] }]
【讨论】: