Ruby循环中管道的用法

时间:2012-07-06 17:01:12

标签: ruby

所以,也许我过于复杂的事情并没有那么难,但是这里有。

在Ruby中,有一种称为.each的循环方法。我认为这很酷 - 但我发现不那么酷的是关于它之后的管道(或Ruby中的任何其他do-type循环)所写的东西的数量。有时管道中只有一件事:

basket.each do |fruit|
    puts "This is a #{fruit}.\n"
end

但有时候,这个管道中有两件事情,如:

contacts.each do |name, profession|
    puts "#{name} is a #{profession}.\n"
end

那么我现在想知道的是,该管道中可能有两个以上的项目吗?就好像我有一个庞大,大而丑陋的多暗阵列一样?

如果我在管道上添加东西并且它们不在那里怎么办?它会给管道中的价值零吗?或者会引发错误?

再次,对不起,如果对于长期的Rubyists来说这是显而易见的,但我来自严格类型变量的土地,我现在也离开了PHP土地。 :)

修改

那么,如果我有这样的事情呢?

categories = [["Bathroom", "Bathroom Fixtures", "Plumbing"],
                      ["Ceiling Fixtures", "Chandeliers", "Flush Mounts", "Mini Chandeliers", "Semi-Flush Mounts", "Pendants", "Track Lighting", "Mini Pendants", "Directional", "Island/Pool Table", "Recessed Lighting"],
                      ["Outdoor", "Exterior", "Landscape Lighting"],
                      ["Fans", "Fans", "Fan Accessories"],
                      ["Lamps", "Lamps", "Shades"],
                      ["Wall Fixtures", "Sconces", "Foyer/Hall Lanterns"],
                      ["Specialty", "Undercabinet", "Light Bulbs", "Lighting Controls", "Glass", "Specialty Items", "Utility"],
                      ["Home Decor", "Decor/Home Accents", "Furniture"]]

我可以像这样循环吗?

categories.each do |category, subcats|
    puts "The main category is #{category} and the sub categories are: "
    subcats.each do |subcat|
        puts "#{subcat}, "
    end
end

4 个答案:

答案 0 :(得分:5)

让我们从分析each方法开始。

a = [1,2,3,4,5]

a.each do |num|
  puts num
end

# 1
# 2
# 3
# 4
# 5

do ... end部分称为block

此块接受一个参数(数组中的元素)

将参数传递给块的方式是使用|

如果您为块提供多个参数:

a.each do |num, x|
  puts num
  puts x
end

# 1
# 
# 2
# 
# 3
# 
# 4
# 
# 5 
# 
每次迭代

x都是nil

让我们自己编写一个使用块的方法,这样你就可以看到它们是如何工作的。

def my_each(a=[])
  a.each do |x|
    yield x if block_given?
  end
end

my_each(a) do |num|
  puts num
end

这里yield x说,执行提供的块并将x传递给它。

如果您将另一个参数传递给block,则为nil。为什么呢?

我们对my_each的实施对第二个参数一无所知,因此它不会yield任何内容,因此它仍为nil

答案 1 :(得分:4)

当你有一个简单的数组时,会发生以下情况:

arr = [1,2,3,4]

arr.each do |x|
  p x
end
1
2
3
4
=> [1,2,3,4]

arr.each do |x,y|
  p x
  p y
end
1
nil
2
nil
3
nil
4
nil
=> [1,2,3,4]

因此,如果ruby不知道将什么放入块参数,它只需将其设置为nil。现在考虑一个嵌套数组:

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

arr.each do |x|
  p x
end
[1, 2]
[3, 4]
[5, 6]
=> [[1,2],[3,4],[5,6]]

arr.each do |x,y|
  p x
  p y
end
1
2
3
4
5
6
=> [[1,2],[3,4],[5,6]]

在这种情况下,ruby假定您要将内部数组的两个元素分配给块变量xy。同样适用于哈希,其中Ruby将键和值分配给xy

hash = {1 => 2, 3 => 4, 5 => 6}

hash.each do |x,y|
  p x
  p y
end
1
2
3
4
5
6
=> {1=>2,3=>4,5=>6}

如果嵌套数组中没有足够的元素,则确实会为块变量分配nil。如果它们太多,它们就会被丢弃:

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

arr.each do |x,y|
  p x
  p y
end
1
2
4
5
6
nil
=> [[1,2,3],[4,5],[6]]

非常简单!

修改

至于您编辑的问题:不,您不能将此1:1应用于Ruby代码,您必须手动将splat运算符(*)应用于subcats。这样,ruby会将所有剩余元素分配给'splatted'块变量:

categories.each do |category,*subcats|
    puts "The main category is #{category} and the sub categories are: "
    subcats.each do |subcat|
        puts "#{subcat}, "
    end
end

虽然我会生成一个以逗号分隔的子类别列表,如下所示:

categories.each do |category,*subcats|
    puts "The main category is #{category} and the sub categories are: "
    puts subcats.join(', ')
end

编辑2

哦,你不会通过为其元素定义很多块参数来处理一个巨大的丑恶的多维数组。您可能会使用嵌套循环迭代它,就像几乎所有其他语言一样,只是因为您永远不知道它包含多少元素。

答案 2 :(得分:1)

您正在谈论的管道是块“变量”的参数列表。实际上这是一种函数指针,管道标记参数列表。

检查array.each

的说明

这不是魔术,参数的数量是在块中定义的,你不能添加更多,如果你这样做,他们就不会得到一个值。原因是“某个时候”可能不止一个,它可能是一个hash.each,它有两个参数,一个键和一个值。

您可以使用块参数read this创建自己的函数。

对于迭代问题,您可以使用散列,也可以编写自己的迭代器。

答案 3 :(得分:1)

块的多个参数

Array#each遍历数组对象,并将单个对象传递给块或返回枚举器。您可以重新定义此行为,但如果您希望一次有多个值,则#each是错误的方法;有关替代方案,请参阅Enumerator#each_slice

数据结构

使用正确的数据结构可以更轻松地解决您的问题。您应该考虑使用散列而不是数组。例如:

categories = 
  {"Bathroom"=>["Bathroom Fixtures", "Plumbing"],
   "Ceiling Fixtures"=>["Chandeliers", "Flush Mounts", "Mini Chandeliers"]}

categories.each do |key, value|
  puts "#{key}:"
  value.each { |v| puts "\t%s" % v }
end

返回:

Bathroom:
    Bathroom Fixtures
    Plumbing
Ceiling Fixtures:
    Chandeliers
    Flush Mounts
    Mini Chandeliers