将哈希键转换为小写 -- Ruby初学者

13

我的表格字段名称都是小写的,而我从CSV文件中获取的字段名称是驼峰式的。有没有办法将哈希数组的键转换为小写?

这是我现在的代码:

    CSV.foreach(file, :headers => true) do |row|
      Users.create!(row.to_hash)
    end

这个失败是因为键值采用了驼峰式(我通过手动编辑文件并将标题行全部转换为小写进行了验证)。

顺便说一句,我想知道为什么Rails会考虑表字段名称的大小写敏感性?

9个回答

26

您可以在CSV中使用header_converters选项:

CSV.foreach(file, :headers => true, :header_converters => lambda { |h| h.try(:downcase) }) do |row|
  Users.create!(row.to_hash)
end

因为空标头会引发异常,所以在这里加上.try非常重要。比每一行都这样做更好(而且更快)。


16
你可以使用类似以下的代码:

You can use something like this:

CSV.foreach(file, :headers => true) do |row|
  new_hash = {}
  row.to_hash.each_pair do |k,v|
   new_hash.merge!({k.downcase => v}) 
  end

  Users.create!(new_hash)
end

我没有时间测试它,但你可以了解一下它的想法。
希望它能有所帮助。


可以运行!但我也很好奇为什么Rails会在这里强制使用大小写(我的文件系统不区分大小写,所以这不是问题)。 - Hopstream
不好意思,我不明白你的意思,什么是“rails takes table field names' case sensitivity into play to begin with?” :) (也许是我的英语不好 :) ) - bor1s
Rails为什么要求表中字段名称的大小写与插入时哈希键匹配? - Hopstream
3
为什么不呢?你的数据库(很可能)是大小写敏感的,Rails 只是简单地传递名称。 - Marnen Laibow-Koser

10

你可以简单地做到

hash.transform_keys(&:downcase)

你可以将哈希键转换为小写,或者根据需要将哈希值转换为小写或大写。

hash.transform_values(&:downcase)hash.transform_values(&:upcase)

hash = {:A=>"b", :C=>"d", :E=>"f"}
hash.transform_keys(&:downcase)
=> {:a=>"b", :c=>"d", :e=>"f"}

6

由于这个标签打了Rails的标记。

从ActiveSupport 3.0开始,您可以使用HashWithIndifferentAccess

这将允许使用小写/大写/符号来访问哈希键。

my_hash = { "camelCase": "some value" }
my_hash.with_indifferent_access[:camelcase] # 'some value'
my_hash.with_indifferent_access['camelcase'] # 'some value'
my_hash.with_indifferent_access['camelCase'] # 'some value'
my_hash.with_indifferent_access['CAMELCASE'] # 'some value'

ActiveSupport 4.0.2还引入了以下内容:

my_hash.deep_transform_keys!(&:downcase)
# or if your hash isn't nested:
my_hash.transform_keys!(&:downcase)

6
with_indifferent_access支持字符串或符号,但对于我来说不是不区分大小写的。ActiveSupport 5.0.4。 - Justin Maxwell
和Justin Maxwell一样。我使用了另一种替代方法。 - el n00b

4
Ruby 1.9提供了一种相当不错的方法来实现这一点,使用each_with_object可以避免初始化临时变量。
CSV.foreach(file, :headers => true) do |row|
  new_hash = row.each_with_object({}) do |(k, v), h|
    h[k.downcase] = v
  end

  Users.create!(new_hash)
end

3
我认为这种方法更加优雅:
hash_with_camelcase_keys.to_a.map { |pair| [pair.first.downcase, pair.last] }.to_h

1
我认为to_a.map { |key, value| [key.upcase.to_s, value] }.to_h更加简洁。 - Sig

1

我会直接添加哈希值,比合并更有效率!因为你不需要为每一对创建一个新的哈希表。

CSV.foreach(file, :headers => true) do |row|
  new_hash = {}
  row.to_hash.each_pair do |k,v|
   new_hash[k.downcase] = v 
  end

  Users.create!(new_hash)
end

1
我发现这个解决方案明显更快,也更符合"Ruby风格"。
CSV.foreach(file, :headers => true) do |row|
  new_hash = Hash[row.to_hash.map { |k, v| [k.downcase, v] }]
  Users.create!(new_hash)
end

不确定它是否更符合 Ruby 的风格 - 它使用了一个类或模块方法,甚至使用了以 ! 结尾的方法。 - shevy

1
你可以考虑使用underscore代替downcase,因为这样也会将CamelCase转换为camel_case表示法,更符合Ruby的风格。
我个人更喜欢使用deep_transform_keyshash.deep_transform_keys{|key| key.underscore.to_sym } 由于transform_keys不能遍历整个哈希表。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接