【问题标题】:Ruby - Access value from json arrayRuby - 从 json 数组访问值
【发布时间】:2017-03-03 22:28:50
【问题描述】:

我正在创建一个字段数组

def create_fields fields
  fields_list = []

  fields.each do |field|
    # puts "adding_field to array: #{field}"
    field_def = { field: field, data: { type: 'Text', description: '' }  }
    fields_list.push field_def
  end
  fields_list
end

fields_list 被设置为 jsonb 字段。

假设我通过了

create_fields ['Ford', 'BMW', 'Fiat']

Json 结果是一个数组:

{"field"=>"Ford", "data"=>{"type"=>"Text", "description"=>""}}
{"field"=>"BMW", "data"=>{"type"=>"Text", "description"=>""}}
{"field"=>"Fiat", "data"=>{"type"=>"Text", "description"=>""}}

如何从 json 数组中访问“福特”?我是否错误地创建了数组?有没有更好的方法来创建这个数组,以便我可以访问我想要的字段?

这个断言通过assert_equal(3, fields.count)

但是我想获得“福特”并检查它的属性,例如type = 'Text',type 可以等于 'Number' 或其他。

【问题讨论】:

  • 你能澄清一下你真正想做的事情吗? Honda 不包含在此处的任何数组中,所以我想知道当它不存在时您想如何访问它?
  • 您确定您的数组包含带有 'field': 'Honda' 的散列吗?
  • @oreoluwa 对不起,我的意思是福特。
  • 您所称的 JSON 结果不是有效的 JSON,也不能转换为 JSON,因为它也不是有效的 Ruby 数组。

标签: ruby-on-rails arrays json ruby


【解决方案1】:

您的 create_fields 方法使用指定参数的结果如下:

[
  {:field=>"Ford", :data=>{:type=>"Text", :description=>""}}, 
  {:field=>"BMW", :data=>{:type=>"Text", :description=>""}},
  {:field=>"Fiat", :data=>{:type=>"Text", :description=>""}}
] 

表示如果要访问属于“福特”的行,需要像这样搜索:

2.3.1 :019 > arr.select{|e| e[:field] == "Ford" }
 => [{:field=>"Ford", :data=>{:type=>"Text", :description=>""}}] 
2.3.1 :020 > arr.select{|e| e[:field] == "Ford" }[0][:data][:type]
 => "Text" 

这不是最优的,因为您需要搜索一个数组 O(n) 而不是使用 hash 的优点。如果有例如:2“福特”行,你会得到一个包含 2 个元素的数组,更难处理字段值的冲突。

如果你创建这样的数组会更好:

def create_fields fields
  fields_list = []

  fields.each do |field|
    # puts "adding_field to array: #{field}"
    field_def = [field, { type: 'Text', description: '' }  ]
    fields_list.push field_def
  end
  Hash[fields_list]
end

如果你选择这个版本,你可以访问这样的成员:

2.3.1 :072 > arr = create_fields ['Ford', 'BMW', 'Fiat']
 => {"Ford"=>{:type=>"Text", :description=>""}, "BMW"=>{:type=>"Text", :description=>""}, "Fiat"=>{:type=>"Text", :description=>""}} 
2.3.1 :073 > arr["Ford"]
 => {:type=>"Text", :description=>""} 
2.3.1 :074 > arr["Ford"][:type]
 => "Text" 

以上两个示例都是 Ruby 字典/哈希。 如果要从中创建 JSON,则需要对其进行转换:

2.3.1 :077 > require 'json'
 => true 
2.3.1 :078 > arr.to_json
 => "{\"Ford\":{\"type\":\"Text\",\"description\":\"\"},\"BMW\":{\"type\":\"Text\",\"description\":\"\"},\"Fiat\":{\"type\":\"Text\",\"description\":\"\"}}" 

【讨论】:

  • 可以帮助简化create_fields 方法的一件事是进行如下映射:Hash[ fields.map { [ field, { ... } ] } ] 尽管为了便于阅读而展开了多个。你的想法是对的,但是创建一个中间变量并推送到一个临时数组实际上比必要的工作要多。
  • 是的,你是对的。有更短、更有效的方法来进行这种转换。我可以从一开始就使用{} 并设置它的元素。不过,这需要最少的修改。
  • 您也可以使用detect 方法代替select :)
  • @AlexGolubenko 是的,但这并不能说明为什么这种数据结构是错误的方法:P
  • @akg 如果你不介意我问的话,最好的数据结构是什么?
【解决方案2】:

这个结构对我来说更适合基于已知键访问值:

def create_fields fields
  fields_hash = {}

  fields.each do |field|
    fields_hash[field] = {type: 'Text', description: ''}
  end
  fields_hash
end

# The hash for fields_hash will look something like this:
{
  Ford: {
    type: "Text",
    description: ""
  },
  BMW: {...},
  Fiat: {...}
}

这将允许您访问如下值:fields[:Ford][:type] in ruby​​ 和 fields.Ford.type in JSON。听起来返回对象比返回数组更容易。您可以通过这种方式更轻松地根据键访问值,并且如果需要,仍然可以选择循环访问对象。

【讨论】:

    【解决方案3】:

    显然,有多种方法可以创建或访问您的数据,但我总是倾向于开发人员选择最适合您的应用程序的数据结构。 在您目前的情况下,为了访问 Ford 哈希,您可以使用 Ruby Array#detect 方法,如下所示:

    ford = fields_list.detect{|field_hash| field_hash['field'] == 'Ford' }
    ford['data'] # => {"type"=>"Text", "description"=>""}
    ford['data']['type'] # => 'Text'
    

    【讨论】:

      【解决方案4】:

      所以,你有你的方法的结果:

      result = 
        [
         {"field"=>"Ford", "data"=>{"type"=>"Text", "description"=>""}},
         {"field"=>"BMW", "data"=>{"type"=>"Text", "description"=>""}},
         {"field"=>"Fiat", "data"=>{"type"=>"Text", "description"=>""}}
        ]
      

      要从中获取“福特”,您可以使用简单的方法detect

      result.detect { |obj| obj['field'] == 'Ford' }
      #=> { "field"=>"Ford", "data"=>{"type"=>"Text", "description"=>""}
      

      另外我建议您编辑您的方法以使其更具可读性:

      def create_fields(fields)
        fields.map do |field|
          {
            field: field,
            data: {
              type: 'Text',
              description: ''
            }
          }
        end
      end
      

      【讨论】:

        猜你喜欢
        • 2013-06-20
        • 1970-01-01
        • 1970-01-01
        • 2012-04-19
        • 2010-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-30
        相关资源
        最近更新 更多