12

我有这样的一行:

<%= f.input :state_id, :input_html => {:value => (policy_address.state.name rescue nil)}, :required => true, :collection => states.map {|s| [ s.name, s.id] }, :include_blank => 'Please select'%>

我想从states.map集合中排除一个值。我认为这会起作用,但它不会:

<%= f.input :state_id, :input_html => {:value => (policy_address.state.name rescue nil)}, :required => true, :collection => states.map {|s| [ s.name, s.id] unless s.name == "excluded_state" }, :include_blank => 'Please select'%>

我输入了unless s.name == "excluded_state,但是,它再次不起作用:

我究竟做错了什么?

4

3 回答 3

26

map不允许跳过值。您必须首先拒绝不需要的元素。

states.reject { |s| s.name == "excluded_state" }.map { |s| [s.name, s.id] }

另一个(更脏的)解决方案是返回nil排除的元素并Array#compact在结果数组上使用以删除这些nil元素:

states.map { |s| s.name == "excluded_state" ? nil : [s.name, s.id] }.compact
于 2012-09-13T14:34:26.960 回答
6

尤里卡的回答很好,但这里只是一个简短的解释,以澄清发生了什么。

map为数组中的每个元素返回一个新数组,其中包含一次运行块的结果。当你写[s.name, s.id] unless s.name == "excluded_state"这会导致块返回nil时,s.name == "excluded_state"即结果将类似于

[["NY", 1], nil, ["CA", 2]]

因此,您可以reject先使用删除不需要的状态,或者您可以只使用compact1删除您最初编写nil的结果中的条目。map


  1. Array#compactnil返回删除所有元素的数组副本。
于 2012-09-13T14:38:09.803 回答
0

提供的答案的另一种选择是使用each_with_item代替map

states.each_with_item([]) { |out, s| out << [s.name, s.id] unless s.name == "excluded_state" }

它介于eachand reduce/之间inject。它接受一个参数,迭代你的可枚举提供参数和元素,然后在最后返回参数。您可以在循环中操纵参数(不这样做没有多大意义)。

于 2021-03-17T19:27:12.037 回答