【问题标题】:Ruby: How to either set a variable to 0 or, if it is already set, increment by 1Ruby:如何将变量设置为 0,或者,如果已经设置,则增加 1
【发布时间】:2009-09-02 18:28:12
【问题描述】:

我知道 ||= 运算符,但认为它在这里对我没有帮助...尝试创建一个数组来计算对象数组中“类型”的数量。

array.each do |c|
  newarray[c.type] = newarray[c.type] ? newarray[c.type]+1 ? 0
end

有没有更优雅的方式来做到这一点?

【问题讨论】:

  • 第二个问号应该是冒号。

标签: ruby arrays


【解决方案1】:
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

【讨论】:

    【解决方案2】:

    使用Array#fetch 方法,如果索引不存在,您可以为其提供默认值:

    array.each do |c|
      newarray[c.type] = newarray.fetch(c.type, -1) + 1
    end
    

    【讨论】:

      【解决方案3】:
      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
      

      【讨论】:

      • 我喜欢你的第二个。唯一的缺点是,后来出现的人可能会认为这是一个错误。如果在生产中使用它,我会添加一个简短的评论来解释我为什么这样做。
      • 我喜欢第二种方式。它有两行,可能有两个作业,但比复杂的条件或任何放在一行上的东西更具可读性。
      【解决方案4】:

      ||= 确实有帮助:

      types = {}
      array.each do |c|
          types[c.class] ||= 0
          types[c.class] += 1
      end
      

      【讨论】:

      • 第一次将其设置为 1... newarray[c.type] ||= -1 newarray[c.type] += 1
      • 是的,这不是我们想要的吗?例如,如果数组为 [1],则类型将变为 {Fixnum=>1}。我们有 1 个 Fixnum。
      • 我们希望它在循环结束时设置为 0,而不是 1,如果 !types[c.class]。
      【解决方案5】:

      你的变量 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}
      

      【讨论】:

        【解决方案6】:

        在 Ruby 1.8.7 或更高版本中,您可以使用 group_by,然后将每个元素列表转换为 count - 1,并从 map 返回的数组中生成哈希。

        Hash[array.group_by(&:class).map { |k,v| [k, v.size-1] }]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-08-27
          • 1970-01-01
          • 1970-01-01
          • 2020-11-07
          • 2023-01-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多