【问题标题】:Display all the values for every date in JSON在 JSON 中显示每个日期的所有值
【发布时间】:2015-09-16 16:48:38
【问题描述】:

我有以下 JSON:

{
    "groups" : [
      {
        "values": "21",
        "date": "2013-02-22"
      },
      {
        "values": "25",
        "date": "2013-02-22"
      },
      {
        "values": "20",
        "date": "2013-02-22"
      },
      {
        "values": "19",
        "date": "2013-02-22"
      },
      {
        "values": "42",
        "date": "2013-02-10"
      },
      {
        "values": "30",
        "date": "2013-02-10"
      },
      {
        "values": "11",
        "date": "2013-02-10"
      }

    ]
}

我已经在 Ruby 类中提取了值和日期。我想找到每个日期的“最高”和“最低”值。我该怎么做?

我还想为它创建并行数组。例如:

low = [12, 22, 11, 45]
high = [34, 50, 15, 60]
dates = ["2013-02-22", "2013-02-10", "2013-02-06", "2013-02-01"]

我还想显示每个日期的所有值。

有人可以给我一些指导吗?

【问题讨论】:

  • 你试过什么? group_by 函数在这里非常有用。
  • 欢迎来到 Stack Overflow。为我们提供最少的输入数据、预期的输出以及重现您所看到的问题所需的最少代码非常重要。最后一部分,重现问题所需的最少代码帮助我们不要尝试所有可能的方法,而是专注于您如何解决问题。就目前而言,您似乎没有尝试过并希望我们为您尝试,或解释如何做到这一点,这两者都不是 SO 的工作原理。
  • 当你在一个问题中给出一个例子时(通常是一件非常好的事情),输入是有效的 Ruby 对象是很重要的。如您所知,JSON 对象是字符串,因此您需要添加单引号'{...}',或者使用%s[...] 或heredoc。此外,您应该将所有输入值分配给变量,以便可以在答案和 cmets 中引用它们而无需定义它们。例如,str = '{...}'`。

标签: ruby json haml


【解决方案1】:

您可以group_by :date 并遍历日期。然后在组中创建一个:values 的数组。

然后使用minmax 获取正确的值,并使用transpose 最终数组来获取您的数组并分配给日期、低位和高位。

json = {
  "groups": [
    { "values": "21", "date": "2013-02-22" },
    { "values": "25", "date": "2013-02-22" },
    { "values": "20", "date": "2013-02-22" },
    { "values": "19", "date": "2013-02-22" },
    { "values": "42", "date": "2013-02-10" },
    { "values": "30", "date": "2013-02-10" },
    { "values": "11", "date": "2013-02-10" }
  ]
}

dates, low, high = json[:groups].group_by { |g| g[:date] }.map do |date, grouped|
  values = grouped.map { |group| group[:values] }
  [date, *values.minmax]
end.transpose
# => => [["2013-02-22", "2013-02-10"], ["19", "11"], ["25", "42"]] 

dates
# => ["2013-02-22", "2013-02-10"]
low
# => ["19", "11"]
high
# => ["25", "42"]

【讨论】:

  • @CarySwoveland 我理解这一点,但我相信刚接触一门语言的人必须始终阅读文档并尝试所有答案方法,看看会发生什么并从中学习。
【解决方案2】:

如果 str 是您的 JSON 字符串:

require 'json'
arr = JSON.parse(str)["groups"]
  #=> [{"values"=>"21", "date"=>"2013-02-22"},
  #    {"values"=>"25", "date"=>"2013-02-22"},
  #    {"values"=>"20", "date"=>"2013-02-22"},
  #    {"values"=>"19", "date"=>"2013-02-22"},
  #    {"values"=>"42", "date"=>"2013-02-10"},
  #    {"values"=>"30", "date"=>"2013-02-10"},
  #    {"values"=>"11", "date"=>"2013-02-10"}] 

by_date = arr.each_with_object(Hash.new {|h,k| h[k] = []}) { |g,h|
  h[g["date"]] << g["values"].to_i }
  # => {"2013-02-22"=>[21, 25, 20, 19], "2013-02-10"=>[42, 30, 11]}

dates = by_date.keys
  #=> ["2013-02-22", "2013-02-10"]     
min_vals, max_vals = *by_date.map { |_,vals| vals.minmax }
  #=> [[19, 25], [11, 42]] 
min_vals
  #=> [19, 25] 
max_vals
  #=> [11, 42] 

Enumerable#each_with_object 方法接受一个参数,该参数是该方法将构造和返回的对象的初始值。它的值由第二个块变量h 给出。我将该参数设为空哈希,并具有块给出的默认值:

{|h,k| h[k] = []}

什么是“默认值”?这意味着如果哈希h 没有键kh[k] 返回一个空数组。让我们看看它是如何工作的。

最初,h #=&gt; {}each_with_object 设置第一个块变量 g 等于 arr 的第一个值:

g = {"values"=>"21", "date"=>"2013-02-22"}

并进行块计算:

h[g["date"]] << g["values"].to_i
  #=> h["2013-02-22"] << 21

由于h没有键"2013-02-22",首先将h["2013-02-22"]设置为等于默认值,一个空数组:

h["2013-02-22"] = []

然后

h["2013-02-22"] << 21
  #=> [21] 
h #=> {"2013-02-22"=>[21]} 

arr 的下一个值被传递给块时:

g = {"values"=>"25", "date"=>"2013-02-22"}

h 同上。所以现在块计算是:

h[g["date"]] << g["values"].to_i
  #=> h["2013-02-22"] << 25
  #=> [21, 25] 
h #=> {"2013-02-22"=>[21, 25]} 

这次不使用默认值,因为h有一个键"2013-02-22"

还有一件事可能需要解释:“splat”*

min_vals, max_vals = *by_date.map { |_,vals| vals.minmax }

我们看到:

by_date.map { |date, vals| vals.minmax }
  #=> [[19, 25], [11, 42]]

如果*by_date.map { |date, vals| vals.minmax } 位于等式的右侧,则splat 会导致[[19, 25], [11, 42]] 的两个元素使用并行赋值 分配给等式左侧的变量。奇怪而美妙的splat operator 需要在每个 Rubiest 的花招中。

由于我没有在块计算中使用date,因此我通过将date 替换为局部变量_ 来引起注意。

编辑:回答您在评论中发布的问题,如果:

id   = [1,1,1,2,2,3,4]
high = [100,100,100,90,90,100,100]
low  = [20,20,20,10,10,30,40]

我正确理解你的问题,你可以先计算:

indices = id.each_with_index.to_a.uniq(&:first).map(&:last)
  #=> [0, 3, 5, 6]

那么你想要的三个数组是:

id.values_at(*indices)
  #=> [1, 2, 3, 4] 
high.values_at(*indices)
  #=> [100, 90, 100, 100] 
low.values_at(*indices)
  #=> [20, 10, 30, 40] 

【讨论】:

  • 优秀。做得好。正是我发布的内容。 by_date.map{ |k, v| [k, v.minmax] }.to_h 也很有用。
  • 卡里,谢谢你的回答。它真的很有帮助。如果我已经在 json 中有高/低值并且我能够用它创建一个数组怎么办?说,我有,high = [100,100,100,90,90,100,100] low = [20,20,20,10,10,30,40]。我还有一组元素的标识符。 id=[1,1,1,2,2,3,4]。如何根据标识符拆分它?我希望结果是high = [100, 90,100,100] low = [20, 10, 30, 40] id = [1,2,3,4]
  • 您必须更具体。可能最好发布另一个问题。
  • 卡里,我已将上述评论编辑得更具体。你明白我的问题了吗?
  • 我刚看到你的评论,但不得不离开。我会在今天晚些时候解决这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多