代码之家  ›  专栏  ›  技术社区  ›  michaelmichael

Ruby中的基本数组迭代

  •  7
  • michaelmichael  · 技术社区  · 15 年前

    在遍历另一个数组时遍历数组的更好方法是什么?例如,如果我有两个数组,如下所示:

    names = [ "Rover", "Fido", "Lassie", "Calypso"]
    breeds = [ "Terrier", "Lhasa Apso", "Collie", "Bulldog"]
    

    假设数组彼此对应—即,Rover是Terrier,Fido是拉萨Apso,等等—我想为每个项目创建一个dog类和一个新dog对象:

    class Dog
      attr_reader :name, :breed
    
      def initialize(name, breed)
        @name = name
        @breed = breed
      end
    end
    

    我可以用以下代码迭代名称和品种:

    index = 0
    
    names.each do |name|
      Dog.new("#{name}", "#{breeds[index]}")
      index = index.next
    end
    

    4 回复  |  直到 15 年前
        1
  •  24
  •   Community CDub    8 年前
    dogs = names.zip(breeds).map { |name, breed| Dog.new(name, breed) }
    

    Array#zip 将目标数组与参数的元素交错,以便

    irb> [1, 2, 3].zip(['a', 'b', 'c'])
     #=> [ [1, 'a'], [2, 'b'], [3, 'c'] ]
    

    nil ).

    irb> [1, 2, 3, 4, 5].zip(['a', 'b', 'c'])
     #=> [ [1, 'a'], [2, 'b'], [3, 'c'], [4, nil], [5, nil] ]
    irb> [1, 2, 3].zip(['a', 'b', 'c', 'd', 'e'])
     #=> [ [1, 'a'], [2, 'b'], [3, 'c'] ]
    

    irb> [1,2,3].zip(['a', 'b', 'c'], [:alpha, :beta, :gamma])
     #=> [ [1, 'a', :alpha], [2, 'b', :beta], [3, 'c', :gamma] ]
    

    Array#map

    irb> [1,2,3].map { |n| 10 - n }
     #=> [ 9, 8, 7 ]
    

    对数组数组使用迭代器时,如果给定多参数块,数组项将自动分解为以下参数:

    irb> [ [1, 'a'], [2, 'b'], [3, 'c'] ].each { |array| p array }
    [ 1, 'a' ]
    [ 2, 'b' ]
    [ 3, 'c' ]
    #=> nil
    irb> [ [1, 'a'], [2, 'b'], [3, 'c'] ].each do |num, char| 
    ...>   puts "number: #{num}, character: #{char}" 
    ...> end
    number 1, character: a
    number 2, character: b
    number 3, character: c
    #=> [ [1, 'a'], [2, 'b'], [3, 'c'] ]
    

    就像 Matt Briggs mentioned , #each_with_index 是另一个值得了解的好工具。它遍历数组的元素,依次为每个元素传递一个块。

    irb> ['a', 'b', 'c'].each_with_index do |char, index| 
    ...>   puts "character #{char} at index #{index}"
    ...> end
    character a at index 0
    character b at index 1
    character c at index 2
    #=> [ 'a', 'b', 'c' ]
    

    使用迭代器时,如 #每个带有索引的\u 可以使用圆括号将数组元素分解为其组成部分:

    irb> [ [1, 'a'], [2, 'b'], [3, 'c'] ].each_with_index do |(num, char), index| 
    ...>   puts "number: #{num}, character: #{char} at index #{index}" 
    ...> end
    number 1, character: a at index 0
    number 2, character: b at index 1
    number 3, character: c at index 2
    #=> [ [1, 'a'], [2, 'b'], [3, 'c'] ]
    
        2
  •  3
  •   Matt Briggs    15 年前
        3
  •  3
  •   Jan Hettich    15 年前

    ++++++++++++++++++++++++++++++++++++++++++

    require 'enumerator'  # needed for Ruby 1.8
    
    names = ["Rover", "Fido", "Lassie", "Calypso"]  
    breeds = ["Terrier", "Lhasa Apso", "Collie", "Bulldog"]
    
    class Dog  
        attr_reader :name, :breed  
    
        def initialize(name, breed)  
            @name = name  
            @breed = breed  
        end  
    end
    
    def bundle(*enumerables)  
        enumerators = enumerables.map {|e| e.to_enum}  
        loop {yield enumerators.map {|e| e.next} }  
    end  
    
    bundle(names, breeds) {|x| p Dog.new(*x) }  
    

    +++++++++++++++++++++++++++++++++++++++++++

    输出:

    #<Dog:0x10014b648 @name="Rover", @breed="Terrier">  
    #<Dog:0x10014b0d0 @name="Fido", @breed="Lhasa Apso">  
    #<Dog:0x10014ab80 @name="Lassie", @breed="Collie">  
    #<Dog:0x10014a770 @name="Calypso", @breed="Bulldog">  
    

        4
  •  2
  •   Andrew Grimm atk    15 年前

    以及 each_with_index (马特提到)有 each_index . 我有时使用它是因为它使程序更加对称,因此会产生错误的代码 look wrong

    names.each_index do |i|
      name, breed = dogs[i], breeds[i] #Can also use dogs.fetch(i) if you want to fail fast
      Dog.new(name, breed)
    end
    
    推荐文章