【问题标题】:Is there an easy way to generate ordered couples in Ruby有没有一种简单的方法可以在 Ruby 中生成有序的情侣
【发布时间】:2014-01-03 16:10:53
【问题描述】:

我想知道是否有类似于 Range 的东西,但不是整数,而是有序对 (x, y)。我想知道是否有一种简单的方法可以做这样的事情:

((1,2)..(5,6)).each {|tmp| puts tmp} #=> (1,2) (3,4) (5,6)

编辑:也许我的问题不是 100% 清楚 :) 我会尝试用不同的方式问。

如果我有这些对:(3,4) 和 (5,6) 我正在寻找一种方法来帮助我生成:

(3,4), (4,5), (5,6)

如果我必须更好地解释它:如果夫妻是 (x,y)->

(x0,y0), ((x0+1),(y0+1)), ((x0+2), (y0+2))  and so on .

【问题讨论】:

    标签: ruby arrays foreach range each


    【解决方案1】:

    您可以使用数组作为 Range 元素,例如:

    > t = [1, 2]..[3, 4]
    => [1, 2]..[3, 4]
    

    但是,它不能被迭代,因为Array 类缺少succ 方法。

    > t.each {|tmp| puts tmp}
    TypeError: can't iterate from Array
            from (irb):5:in `each'
            from (irb):5
            from D:/Programmes/Ruby/bin/irb:12:in `<main>'
    

    因此,如果您想允许使用数组进行迭代,请定义一个 Array#succ 方法来满足您的需求:

    class Array
      def succ
        self.map {|elem| elem + 1 }
      end
    end
    

    给你:

    > t = [1, 2]..[3, 4]
    => [1, 2]..[3, 4]
    > t.each {|tmp| p tmp}
    [1, 2]
    [2, 3]
    [3, 4]
    => [1, 2]..[3, 4]
    

    【讨论】:

    • 感谢您的回答。我知道猴子修补不是一件好事,但是。说到有没有类似的方法来得到这个:[[5,4], [4,5], [3,6]] 如果我有 [5,4] 和 [3,6]?它与第一个逻辑不完全相同,但具有相同的语义。我很好奇。
    • 为什么方法的名字必须是'succ'?
    • @user2128702 见ruby-doc.org/core-2.0.0/Range.html#method-i-each“只有在范围的开始对象支持succ方法时才能使用each方法。”。如果您想要自定义中间数组,可能需要另一种方法
    【解决方案2】:

    您可以使用Enumerable#each_slice

    1.9.3-p327 :001 > (1..6).each_slice(2).to_a
     => [[1, 2], [3, 4], [5, 6]] 
    

    【讨论】:

    • 谢谢,但我没有以正确的方式问这个问题。现在有一个修改。
    • 哦,好吧,我想 SirDarius 回答了你的问题。
    【解决方案3】:

    Ruby 是一种面向对象的语言。所以,如果你想用“有序的情侣对象”做某事,那么你需要……嗯……一个OrderedCouple对象。

    class OrderedCouple < Struct.new(:x, :y)
    end
    
    OrderedCouple.new(3, 4)
    # => #<struct OrderedCouple x=3, y=4>
    

    呃,看起来很难看:

    class OrderedCouple
      def to_s; "(#{x}, #{y})" end
    
      alias_method :inspect, :to_s
    
      class << self; alias_method :[], :new end
    end
    
    OrderedCouple[3, 4]
    # => (3, 4)
    

    Ranges 用于两件事:检查包含和迭代。为了将对象用作Range 的起点和终点,它必须响应&lt;=&gt;。如果你也想遍历Range,那么起始对象必须响应succ

    class OrderedCouple
      include Comparable
    
      def <=>(other)
        to_a <=> other.to_a
      end
    
      def to_a; [x, y] end
    
      def succ
        self.class[x.succ, y.succ]
      end
    end
    
    puts *OrderedCouple[1, 2]..OrderedCouple[5, 6]
    # (1, 2)
    # (2, 3)
    # (3, 4)
    # (4, 5)
    # (5, 6)
    

    【讨论】:

      【解决方案4】:

      试试这个,

      def tuples(x, y)
        return enum_for(:tuples, x, y) unless block_given?
        (0..Float::INFINITY).each { |i| yield [x + i, y + i] }
      end
      

      然后,

      tuples(1,7).take(4) 
      # or
      tuples(1,7).take_while { |x, y| x <= 3 && y <= 9 } 
      

      都返回

      [[1, 7], [2, 8], [3, 9]]
      

      【讨论】:

        猜你喜欢
        • 2011-01-03
        • 2011-01-27
        • 2010-09-06
        • 2012-04-30
        • 1970-01-01
        • 1970-01-01
        • 2011-01-29
        • 2011-03-02
        • 1970-01-01
        相关资源
        最近更新 更多