【问题标题】:Ruby: Extract elements from deeply nested JSON structure based on criteriaRuby:根据标准从深度嵌套的 JSON 结构中提取元素
【发布时间】:2017-04-03 13:45:25
【问题描述】:

想要从每个具有marketName == 'Moneyline' 的市场中提取每个marketID。尝试了.maps、.rejects 和/或.selects 的几种组合,但由于复杂的结构让我感到困惑,因此无法缩小范围。

events中有很多marketsevents也有很多。结构示例(为简洁起见尝试对其进行编辑):

{"currencyCode"=>"GBP",
"eventTypes"=>[
    {"eventTypeId"=>6423,
    "eventNodes"=>[
        {"eventId"=>28017227,
        "event"=>
            {"eventName"=>"Philadelphia @ Seattle"
            },
            "marketNodes"=>[
                {"marketId"=>"1.128274650",
                "description"=>
                    {"marketName"=>"Moneyline"}
                },
                {"marketId"=>"1.128274625",
                "description"=>
                    {"marketName"=>"Winning Margin"}
                }}}]},
        {"eventId"=>28018251,
        "event"=>
            {"eventName"=>"Arkansas @ Mississippi State"
            },
            "marketNodes"=>[
                {"marketId"=>"1.128299882",
                "description"=>
                    {"marketName"=>"Under/Over 60.5pts"}
                },
                {"marketId"=>"1.128299881",
                "description"=>
                    {"marketName"=>"Moneyline"}
                }}}]},
        {"eventId"=> etc....

尝试了各种各样的东西,例如,

markets = json["eventTypes"].first["eventNodes"].map {|e| e["marketNodes"].map { |e| e["marketId"] } if (e["marketNodes"].map {|e| e["marketName"] == 'Moneyline'})}
markets.flatten
# => yields every marketId not every marketId with marketName of 'Moneyline'

从 Moneyline 市场获取包含每个 marketId 的简单数组,无需其他信息就足够了。如果愿意,也可以使用 Rails 方法。

对不起,如果我的编辑弄乱了语法。 Here's the source。解析 JSON 后,仅使用 => 而不是 : 看起来像这样。

谢谢!

【问题讨论】:

  • 而不是使用外部资源。这是在 Rails 应用程序中,所以使用 ruby​​ 或 rails 方法
  • 你有语法正确的例子吗?
  • @EricDuminil 抱歉,如果我的编辑搞砸了。见这里:betfair.com/www/sports/exchange/readonly/v1/… 在我的控制台中,它基本上看起来与解析后只有=> 而不是: 完全一样。有点乱。

标签: arrays json ruby hash


【解决方案1】:

我喜欢嵌套地图和选择:D

require 'json'

hash = JSON.parse(File.read('data.json'))

moneyline_market_ids = hash["eventTypes"].map{|type|
  type["eventNodes"].map{|node|
    node["marketNodes"].select{|market|
      market["description"]["marketName"] == 'Moneyline'
    }.map{|market| market["marketId"]}
  }
}.flatten

puts moneyline_market_ids.join(', ')
#=> 1.128255531, 1.128272164, 1.128255516, 1.128272159, 1.128278718, 1.128272176, 1.128272174, 1.128272169, 1.128272148, 1.128272146, 1.128255464, 1.128255448, 1.128272157, 1.128272155, 1.128255499, 1.128272153, 1.128255484, 1.128272150, 1.128255748, 1.128272185, 1.128278720, 1.128272183, 1.128272178, 1.128255729, 1.128360712, 1.128255371, 1.128255433, 1.128255418, 1.128255403, 1.128255387

【讨论】:

  • 约扎。完美的。非常感谢你!想弄清楚我的头很痛。
  • 嘿@eric-duminil,如果你有时间,我这里有一个更具挑战性的脑筋急转弯。来源:betfair.com/www/sports/exchange/readonly/v1/…。我想选择marketIds == 'Moneyline',但只选择countryCode == 'US' || 'GB'eventName.include?(' @ ')。 (space@ 之前和之后)。我尝试了mapselect 的不同组合,但有些节点没有'countryCode',这会使事情复杂化。最后两个标准有一些重叠,所以uniq 可能是必要的吗? TIA!
  • 请再写一个问题。
  • 对! stackoverflow.com/questions/40708340/…。真的很感激!
【解决方案2】:

只是为了好玩,这是另一个可能的答案,这次是使用正则表达式。它更短,但可能会根据您的输入数据而中断。它直接将 json 数据作为 String 读取:

json = File.read('data.json')

market_ids   = json.scan(/(?<="marketId":")[\d\.]+/)
market_names = json.scan(/(?<="marketName":")[^"]+/)

moneyline_market_ids = market_ids.zip(market_names).select{|id,name| name=="Moneyline"}.map{|id,_| id}
puts moneyline_market_ids.join(', ')
#=> 1.128255531, 1.128272164, 1.128255516, 1.128272159, 1.128278718, 1.128272176, 1.128272174, 1.128272169, 1.128272148, 1.128272146, 1.128255464, 1.128255448, 1.128272157, 1.128272155, 1.128255499, 1.128272153, 1.128255484, 1.128272150, 1.128255748, 1.128272185, 1.128278720, 1.128272183, 1.128272178, 1.128255729, 1.128360712, 1.128255371, 1.128255433, 1.128255418, 1.128255403, 1.128255387

它输出与另一个答案相同的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-08
    • 2020-11-07
    • 2021-07-18
    • 2020-03-19
    • 1970-01-01
    • 2018-08-30
    • 2012-09-16
    相关资源
    最近更新 更多