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

Ruby on rails 用于比较和选择2D数组中的值的最优雅的Ruby表达式是什么?,ruby-on-rails,arrays,loops,coding-style,expression,Ruby On Rails,Arrays,Loops,Coding Style,Expression,我有一些代码,可以快速浏览一组Rails活动记录模型,并根据2D数组中的相关值设置属性 我基本上是在一个美国州表中设置一个美国州缩写代码,该表以前只存储全名。一个州名称库用于派生缩写,它包含一个二维数组,每个子数组都有一个全名和一个缩写(即,[[['New York','NY']['Pennsylvania','PA'][etc]])。我将数据库中每个记录的状态名与该数组中的每个全文名进行比较,然后在存在匹配项时获取相应的同级数组单元格 这段代码工作正常,并产生正确的结果,但它看起来很简陋,如果

我有一些代码,可以快速浏览一组Rails活动记录模型,并根据2D数组中的相关值设置属性

我基本上是在一个美国州表中设置一个美国州缩写代码,该表以前只存储全名。一个州名称库用于派生缩写,它包含一个二维数组,每个子数组都有一个全名和一个缩写(即,
[[['New York','NY']['Pennsylvania','PA'][etc]]
)。我将数据库中每个记录的状态名与该数组中的每个全文名进行比较,然后在存在匹配项时获取相应的同级数组单元格

这段代码工作正常,并产生正确的结果,但它看起来很简陋,如果不阅读很多行代码,就很难理解:

# 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
条件来表达这一点?

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

使用现有的2D数组,您可以调用
以获取
散列
,其中

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

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

使用现有的2D数组,您可以调用
以获取
散列
,其中

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

是的,有一些不需要的
if
s和check

由于它是Rails,即使它没有声明有问题的标记,您可能希望使用,这是迭代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
还要注意,这会绕过任何验证,如果希望保持对象有效,请坚持使用。 最后一件事——将其全部打包,这样,如果出现任何问题,它将回滚任何更改

    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

是的,有一些不需要的
if
s和check

由于它是Rails,即使它没有声明有问题的标记,您可能希望使用,这是迭代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
还要注意,这会绕过任何验证,如果希望保持对象有效,请坚持使用。 最后一件事——将其全部打包,这样,如果出现任何问题,它将回滚任何更改

    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

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

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

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

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

为什么这会被否决?到目前为止,我已经测试了所有提交的答案,而这一个对我来说似乎是最简单、最优雅的。它产生了正确的结果。@Todd我没有投反对票,但我想一个原因是使用纯Ruby,这在AR方面效率极低,因为它在任何处理之前都会加载整个表数据。当涉及到大量内存时,它很容易导致内存过载data@AndreyDeineko谢谢,这很有道理。幸运的是,这是在迁移过程中进行的,只有51条记录,而且无论如何都需要选择整个表。@Todd迁移与否没有任何区别-选择整个数据库可以用很少的其他方法,使用Ruby是一种罪过:)以防万一你会对AR优化感兴趣-在我的回答中,我给了你一些提示。@Todd我要小心将数据更改放在迁移中,这通常被认为是不好的做法。在我看来,您应该在临时rake任务中进行数据更改。为什么这会被否决?到目前为止,我已经测试了所有提交的答案,而这一个对我来说似乎是最简单、最优雅的。它产生了正确的结果。@Todd我没有投反对票,但我想一个原因是使用纯Ruby,这在AR方面效率极低,因为它在任何处理之前都会加载整个表数据。当涉及到大量内存时,它很容易导致内存过载data@AndreyDeineko谢谢,这很有道理。幸运的是,这是在迁移过程中进行的,只有51条记录,而且无论如何都需要选择整个表。@Todd迁移与否没有任何区别-选择整个数据库可以用很少的其他方法,使用Ruby是一种罪过:)以防万一你会对AR优化感兴趣-在我的回答中,我给了你一些提示。@Todd我要小心将数据更改放在迁移中,这通常被认为是不好的做法。在我看来,您应该在临时rake任务中进行数据更改。4点:1)Ruby没有“2D”或“nD”数组的概念;2) 您可能会发现,将哈希与诸如
“New York”=>“NY”
之类的元素一起使用比较方便,而不是
[“New York”,“NY”]
;3) 您可以将部分代码简化为
States::USA.each{s|break named_state.update_列(:code,s[1]),如果s[0]==named_state.name}
。(参见)4)一个具有预期结果的示例将非常有用。将每个输入分配给一个变量,这样读者就可以在答案和注释中引用这些变量,而无需定义它们。你需要一个Rails或ActiveRecord标记。4点:1)Ruby没有“2D”或“nD”数组的概念;2) 您可能会发现,将哈希与诸如
“New York”=>“NY”
之类的元素一起使用比较方便,而不是
[“New York”,“NY”]
;3) 您可以将部分代码简化为
States::USA.each{s|break named_state.update_列(:code,s[1]),如果s[0]==named_state.name}
。(参见)4)一个具有预期结果的示例将非常有用。将每个输入分配给一个变量,这样读者就可以在答案和注释中引用这些变量,而无需定义它们。