用于比较和选择2D数组中的值的最优雅的Ruby表达式是什么?

时间:2015-12-03 21:43:33

标签: ruby-on-rails arrays loops coding-style expression

我有一些代码正在通过一组Rails Active Record模型,并根据2D数组中的相关值设置属性。

我基本上在美国国家的表格中设置美国州的缩写代码,该表格以前只存储全名。正在使用状态名称库来导出缩写,它包含一个2D数组,每个子数组都有一个全名和一个缩写(即[['New York', 'NY']['Pennsylvania', 'PA'][etc]])。我将数据库中每条记录的状态名称与此Array中的每个全文名称进行比较,然后在匹配时获取相应的兄弟Array单元格。

此代码工作正常,并产生正确的结果,但它看起来很邋and,如果不阅读很多行就不容易理解:

# For the following code, StatesWithNames is an Active Record model, which is
#  having a new column :code added to its table.
# Sates::USA represents a 2D Array as: [['StateName', 'NY']], and is used to 
#  populate the codes for StatesWithNames. 
# A comparison is made between StatesWithNames.name and the text name found in
#  States::USA, and if there is a match, the abbreviation from States::USA is
#  used
if StatesWithNames.any? 
  StatesWithNames.all.each do |named_state|
    if named_state.code.blank?
      States::USA.each do |s|
        if s[0] == named_state.name
          named_state.update_column(:code, s[1])
          break
        end
      end
    end
  end
end

用这种逻辑表达赋值的最Ruby方式是什么?我尝试了几个不同的过程/块,但达到了更复杂的表达式或不正确的结果。是否有更简单的方法可以用更少的行和/或if-end条件表达它?

3 个答案:

答案 0 :(得分:2)

是的,有一些if和支票,不需要。

因为它是Rails,即使它没有在问题的标签中说明,你可能想要使用find_each,这是迭代AR集合的最有效方式之一:

  StatesWithNames.find_each do |named_state|
    next unless named_state.code.blank?
    States::USA.each do |s|
      named_state.update_column(:code, s[1]) if s[0] == named_state.name       
    end
  end

另请注意,update_column绕过任何验证,如果您希望保持对象有效,请坚持update!。 最后一件事 - 将它全部包装在transaction中,所以如果一直出现任何问题 - 它会回滚任何更改。

    StatesWithNames.transaction do
      StatesWithNames.find_each do |named_state|
        next unless named_state.code.blank?
        States::USA.each do |s|
          named_state.update!(:code, s[1]) if s[0] == named_state.name       
        end
      end
    end

答案 1 :(得分:1)

您可以为此使用不同的数据结构。

使用现有的2D数组,您可以在其上调用to_h以获得Hash其中

a = [['California', 'CA'], ['Oregon', 'OR']].to_h
=> { 'California' => 'CA', 'Oregon' => 'OR' }

然后在你的代码中你可以做

state_hash = States::USA.to_h

if StatesWithNames.any? 
  StatesWithNames.all.each do |named_state|
    if named_state.code.blank?
      abbreviation = state_hash[named_state.name]
      if !abbreviation.nil?
        named_state.update_column(:code, abbreviation)
      end
    end
  end
end

答案 2 :(得分:0)

您要做的第一件事是将查找从数组数组转换为哈希。

state_hash = States::USA.to_h

if StatesWithNames.any?
  StatesWithNames.all.select{|state| state.code.blank?}.each do |named_state|
    named_state.update_column(:code, state_hash[named_state.name]) if state_hash[named_state.name]
  end
end