遍历数组并在Ruby中一行中初始化多个变量

问题描述

我正在尝试遍历数组并计算数组中正数,负数和零的数目。现在我正在这样做

arr = [1,-1,2,3,-2,-5]

pos = arr.select { |i| i > 0 }.count
neg = arr.select { |i| i < 0 }.count
zero = arr.select { |i| i == 0 }.count

puts pos
puts neg
puts zero

但是有什么办法可以我一行完成吗?像这样吗?

pos,neg,zero = arr.select { |i| i > 0; i < 0; i == 0; }.count

解决方法

使用inject<=>运算符:

neg,zero,pos = arr.inject([0,0]) { |a,b| a[(b<=>0)+1] += 1; a }

或者,如@HolgerJust所述:

neg,pos = arr.each_with_object([0,b| b[(a<=>0)+1] += 1 }

稍长一些,但块中没有多余的; a


受@steenslag使用tally的启发:

neg,pos = arr.map { |x| x<=>0 }.tally.values_at(-1,1)
,

如果使用计数哈希,则代码很短,结果以哈希返回,这可能很方便。

arr = [1,-1,2,3,-2,-5,4]

你可以写

arr.each_with_object(Hash.new(0)) { |n,h| h[n<=>0] += 1 }
  #=> {1=>4,-1=>3,0=>1}

或者您可能更喜欢

labels = { -1=>:neg,0=>:zero,1=>:pos }
arr.each_with_object(Hash.new(0)) { |n,h| h[labels[n<=>0]] += 1 }
  #=> {:pos=>4,:neg=>3,:zero=>1}

最后一行也可以写成

arr.each_with_object({}) { |n,h| h[labels[n<=>0]] = (h[labels[n<=>0]] ||= 0) + 1 }

请参见Hash::new,特别是(第二种)形式,该形式采用称为默认值(此处为零)的参数,并且不包含任何块。如果定义了哈希h = Hash.new(0),则如果h没有密钥k,则h[k]返回0(并且h不变)。

,
arr = [1,-5]
neg,pos = arr.map{|n| n <=> 0}.tally.values_at(-1,1)

使用新的tally方法。

,

正如其他人已经说过的那样,您应该只使用运算符使用注入和计数。如果您打算频繁使用类似的逻辑,则可以像这样将猴子#tally_by方法修补到Enumerable中:

class Enumerable
    def my_tally(*keys,&proc)
        proc ||= -> e {e}    # Default identity proc
        h = keys.empty? ? Hash.new(0) : Hash[keys.map{|k|[k,0]}]
        inject(h){|a,e| a[proc.call(e)] += 1; a}
    end
end

这允许您编写:

neg,pos = arr.my_tally(-1,1){|e| e <=> 0}

虽然这肯定比其他代码更高级,但是如果您发现自己经常使用类似的逻辑,那就更好了。如果您不喜欢猴子修补,也可以将其作为常规方法。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...