2

我发现自己在 Ruby 中经常使用类似 PHP 的循环,而当语言的其余部分如此简洁时,我感觉很不对劲。我结束了这样的代码:

conditions_string = ''

zips.each_with_index do |zip, i|

    conditions_string << ' OR ' if i > 0
    conditions_string << "npa = ?"

end

# Now I can do something with conditions string

我觉得我应该能够做这样的事情

conditions_string = zips.each_with_index do |zip, i|

    << ' OR ' if i > 0
    << "npa = ?"

end

是否有一种“整洁”的方式在 Ruby 中使用块设置变量?

4

5 回答 5

4

我首先想到的是这样的:

a = %w{array of strings}             => ["array", "of", "strings"]
a.inject { |m,s| m + ' OR ' + s }    => "array OR of OR strings"

但这可以做到

a.join ' OR '

虽然我认为您很快就会需要该构造,但要复制您的确切示例,我可能会使用:

([' npa = ? '] * a.size).join 'OR'
于 2009-12-01T23:24:11.357 回答
4

由于您实际上并没有使用 zip 的值,我建议

zips.map {|zip| "npa = ?" }.join(" OR ")

但总的来说,我建议查看 Enumerable#inject 函数以避免这种循环。

于 2009-12-01T23:25:41.727 回答
1

你似乎没有zip在你的循环中访问,所以以下应该工作:

conditions_string = (['npa = ?'] * zips.length).join(' OR ')

如果您需要访问zip,那么您可以使用:

conditions_string = zips.collect {|zip| 'npa = ?'}.join(' OR ')
于 2009-12-01T23:21:16.183 回答
1

尽管其他人为您的特定问题提供了更惯用的解决方案,但实际上有一个很酷的方法Object#instance_eval,这是许多 Ruby DSL 使用的标准技巧。它设置为其块内self的接收者:instance_eval

简短的例子:

x = ''
x.instance_eval do
    for word in %w(this is a list of words)
        self << word  # This means ``x << word''
    end
end
p x
# => "thisisalistofwords"

它并没有像 Perl 那样普遍涵盖所有内容$_,但它允许您将方法隐式发送到单个对象。

于 2009-12-02T09:20:51.947 回答
0

在 1.8.7+ 中,您可以使用each_with_object

它将 DigitalRoss 的“注入”成语替换为:

a = %w{hello my friend}  => ["hello", "my", "friend"]
a.each_with_object("") { |v, o| o << v << " NOT " }  => "hello NOT my NOT friend NOT"
于 2009-12-02T09:05:58.197 回答