簡體   English   中英

Ruby中的基本數組迭代

[英]Basic Array Iteration in Ruby

在遍歷另一個數組時遍歷數組的更好方法是什么? 例如,如果我有兩個如下數組:

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

假設數組相互對應-即Rover是Terrier,Fido是Lhasa 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

但是,我感到使用index變量是錯誤的處理方式。 有什么更好的方法?

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 提到的那樣#each_with_index是另一個#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' ]

當使用像#each_with_index這樣的迭代器時,可以使用括號將數組元素分解為它們的組成部分:

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'] ]

想到了each_with_index ,這是您執行此操作的更好方法。 但是,rampion的總體答案更好,這種情況就是zip的目的。

改編自Flanagan和Matz的“ Ruby編程語言”,第5.3.5節“外部迭代器”,示例5-1,p。 139:

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

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">  

我想這就是我們想要的!

each_with_index (由Matt提到)一樣,還有each_index 我有時會使用它,因為它使程序更對稱,因此錯誤的代碼將看起來是錯誤的

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM