Setting variables with blocks in ruby

雨燕双飞 提交于 2019-12-13 15:55:09

问题


I find myself using PHP-like loops a lot in Ruby and it feels wrong when the rest of the language is so neat. I wind up with code like this:

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

I feel like I should be able to do something like this

conditions_string = zips.each_with_index do |zip, i|

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

end

Is there a 'Neat' way to set a variable with a block in Ruby?


回答1:


You don't seem to be accessing zip in your loop, so the following should work:

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

If you need access to zip, then you could use:

conditions_string = zips.collect {|zip| 'npa = ?'}.join(' OR ')



回答2:


Since you don't actually use the value of zip, I'd suggest

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

but in general I'd suggest looking at the Enumerable#inject function to avoid this kind of loops.




回答3:


The first thing I thought of was this:

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

But that can be done with just

a.join ' OR '

And while I think you will need that construct soon, to duplicate your exact example I might just use:

([' npa = ? '] * a.size).join 'OR'



回答4:


Although others have given more idiomatic solutions to your specific problem, there's actually a cool method Object#instance_eval, which is a standard trick that many Ruby DSLs use. It sets self to the receiver of instance_eval inside its block:

Short example:

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"

It doesn't pervasively cover everything in the way Perl's $_ does, but it allows you to implicitly send methods to one single object.




回答5:


In 1.8.7+ you can use each_with_object

It replaces DigitalRoss's 'inject' idiom with this:

a = %w{hello my friend}  => ["hello", "my", "friend"]
a.each_with_object("") { |v, o| o << v << " NOT " }  => "hello NOT my NOT friend NOT"


来源:https://stackoverflow.com/questions/1829621/setting-variables-with-blocks-in-ruby

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!