【问题标题】:How to group Date and time data from API如何从 API 对日期和时间数据进行分组
【发布时间】:2017-04-10 19:15:25
【问题描述】:

我正在尝试对从 API 获取的数据进行分组,以提供给我们的前端应用程序。我的意思是按“日期”分组“时间”。 日期:{date1: [time1, time2, timeN], date2: [time1...]}

我的输入是这样的:

{"date"=>"2017-04-04T00:00:00", "time"=>"1754-01-01T13:00:00"}
{"date"=>"2017-04-04T00:00:00", "time"=>"1754-01-01T14:00:00"}
{"date"=>"2017-04-05T00:00:00", "time"=>"1754-01-01T12:00:00"}
{"date"=>"2017-04-05T00:00:00", "time"=>"1754-01-01T13:00:00"}

我的输出应该是这样的:

dates: [{date: "2017-04-04T00:00:00", availableTimes: ["1754-01-01T13:00:00", "1754-01-01T14:00:00"]}, {date: "2017-04-05T00:00:00", availableTimes: ["1754-01-01T12:00:00", "1754-01-01T13:00:00"]}]

我正在尝试这样做,但不会陷入疯狂循环。我有以下内容:

dates  = Hash[input_data.map{|sd| [sd.date, [""]]}]

这给了我这样的数据输出:

{"2017-04-04T00:00:00"=>[""],
 "2017-04-05T00:00:00"=>[""],
 "2017-04-11T00:00:00"=>[""],
 "2017-04-12T00:00:00"=>[""],
 "2017-04-18T00:00:00"=>[""],
 "2017-04-19T00:00:00"=>[""],
 "2017-04-25T00:00:00"=>[""],
 "2017-04-26T00:00:00"=>[""]}

【问题讨论】:

  • 只是好奇:这个时间格式是什么? 1754-01-01 是什么?
  • 其实我不知道,只是从 API 接收到这个信息,它现在是虚拟数据,所以这可能是日期像 1754 的原因:P

标签: ruby date parsing ruby-hash


【解决方案1】:

只有一种可能的方式:

input.each_with_object(Hash.new { |h, k| h[k] = [] }) do |h, m|
  m[h['date']] << h['time']
end.map { |k, v| { date: k, avaliable_times: v } }
#=> [{:date=>"2017-04-04T00:00:00", :avaliable_times=>["1754-01-01T13:00:00", "1754-01-01T14:00:00"]},
#    {:date=>"2017-04-05T00:00:00", :avaliable_times=>["1754-01-01T12:00:00", "1754-01-01T13:00:00"]}]

实际上,如果没有最后一个map,您的数据结构似乎会更简洁,我的意思是:

#=> {"2017-04-04T00:00:00"=>["1754-01-01T13:00:00", "1754-01-01T14:00:00"],
#    "2017-04-05T00:00:00"=>["1754-01-01T12:00:00", "1754-01-01T13:00:00"]}

【讨论】:

  • 确实如此。使用第二种格式会更容易/更快。
【解决方案2】:

您正在获得该输出,因为您的 map 函数实际上并未修改任何类型的数据结构。它只是返回一个新数组,其中包含包含日期的数组和一个空字符串的数组。基本上,这不会仅通过一次 map 调用来完成。

所以,基本算法是:

  1. 查找所有唯一日期的数组
  2. 遍历唯一日期并使用select 仅获取循环迭代中当前日期的日期/时间对
  3. 以您喜欢的格式设置数据

此代码将具有filteredDates 为您需要的数据格式

filteredDates = { dates: [] }
uniqueDates = input_data.map { |d| d["date"] }.uniq # This is an array of only unique dates
uniqueDates.each do |date|
    dateTimes = input_data.select { |d| d["date"] == date }
    newObj = { date: date }
    newObj[:availableTimes] = dateTimes.map { |d| d["time"] }
    filteredDates[:dates].push(newObj)
end

这是filteredDates 的样子:

{:dates=>[{:date=>"2017-04-04T00:00:00", :availableTimes=>["1754-01-01T13:00:00", "1754-01-01T14:00:00"]}, {:date=>"2017-04-05T00:00:00", :availableTimes=>["1754-01-01T12:00:00", "1754-01-01T13:00:00"]}]}

【讨论】:

    【解决方案3】:

    有很多方法可以做到这一点,一种方法是创建一个新的哈希,并将默认值设置为一个数组,然后循环遍历结果并插入日期:

    dates = Hash.new { |hash, key| hash[key] = [] }
    input_data.each{ |sd| dates[sd["date"]] << sd["time"] }
    

    【讨论】:

    • 这会返回{"2017-04-04T00:00:00"=&gt;["1754-01-01T13:00:00", "1754-01-01T14:00:00"], "2017-04-05T00:00:00"=&gt;["1754-01-01T12:00:00", "1754-01-01T13:00:00"]},这不是必需的格式。另外,应该注意的是,这不会返回dates 的新值。例如,如果它被包装在一个方法中,则需要最后一行 dates
    • 我建议您熟悉each_with_object
    【解决方案4】:

    我会使用Enumerable#group_by

    dates = [{"date"=>"2017-04-04T00:00:00", "time"=>"1754-01-01T13:00:00"},
             {"date"=>"2017-04-04T00:00:00", "time"=>"1754-01-01T14:00:00"},
             {"date"=>"2017-04-05T00:00:00", "time"=>"1754-01-01T12:00:00"},
             {"date"=>"2017-04-05T00:00:00", "time"=>"1754-01-01T13:00:00"}]
    
    dates.group_by { |g| g["date"] }.
          map { |k,v| { date: k, available_times: v.map { |h| h["time"] } } }
      #=> [{:date=>"2017-04-04T00:00:00",
      #     :available_times=>["1754-01-01T13:00:00", "1754-01-01T14:00:00"]},
      #    {:date=>"2017-04-05T00:00:00",
      #     :available_times=>["1754-01-01T12:00:00", "1754-01-01T13:00:00"]}] 
    

    第一步产生以下中间值:

    dates.group_by { |g| g["date"] }      
      #=> {"2017-04-04T00:00:00"=>
      #     [{"date"=>"2017-04-04T00:00:00", "time"=>"1754-01-01T13:00:00"},
      #      {"date"=>"2017-04-04T00:00:00", "time"=>"1754-01-01T14:00:00"}],
      #    "2017-04-05T00:00:00"=>
      #     [{"date"=>"2017-04-05T00:00:00", "time"=>"1754-01-01T12:00:00"},
      #      {"date"=>"2017-04-05T00:00:00", "time"=>"1754-01-01T13:00:00"}]}
    

    【讨论】:

    • 我也想过group_by,但对使用嵌套map感到困惑:)。
    【解决方案5】:

    可能还有更优雅的方式,但是

    results = Hash.new
    dates.each do |date|
      d, t = date['date'].split('T') # (clean up/split date and time formatting)
      results.key?(d) ? nil : results[d] = Array.new
      results[d] << t
    end
    puts results
    # => {"2017-04-04"=>["13:00:00", "14:00:00"], "2017-04-05"=>["12:00:00", "13:00:00"]}
    

    【讨论】:

      猜你喜欢
      • 2019-09-07
      • 2023-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-28
      • 1970-01-01
      • 2014-12-23
      • 2021-12-25
      相关资源
      最近更新 更多