2

我有一个看起来像这样的数组:

[
    {"timestamp" => 1347119549, "category" => nil},
    {"timestamp" => 1347119547, "category" => "Monkeys"},
    {"timestamp" => 1347119543, "category" => nil},
    {"timestamp" => 1347119542, "category" => "Monkeys"}
]

我想按时间戳(降序)对其进行排序,除非它的类别不是 nil,在这种情况下,它应该与它的“兄弟姐妹”一起出现,即使它比未分类的条目“旧”。我需要对这个数组进行排序,所以它看起来像这样:

[
    {"timestamp" => 1347119549, "category" => nil},
    {"timestamp" => 1347119547, "category" => "Monkeys"},
    {"timestamp" => 1347119542, "category" => "Monkeys"},
    {"timestamp" => 1347119543, "category" => nil}
]

我试图弄清楚如何使用group_byand获得正确的结果sort,但没有成功。

4

4 回答 4

2
require 'pp'

ar = [
    {"timestamp" => 1347119549, "category" => nil},
    {"timestamp" => 1347119547, "category" => "Monkeys"},
    {"timestamp" => 1347119543, "category" => nil},
    {"timestamp" => 1347119542, "category" => "Monkeys"}
]

pp ar.group_by{|h| h['category'] ? h['category'] : h['timestamp']}.
   map{|k,v| v.sort_by{|h| -h['timestamp']}}.
   sort_by{|a| -a[0]['timestamp']}.flatten
# >> [{"timestamp"=>1347119549, "category"=>nil},
# >>  {"timestamp"=>1347119547, "category"=>"Monkeys"},
# >>  {"timestamp"=>1347119542, "category"=>"Monkeys"},
# >>  {"timestamp"=>1347119543, "category"=>nil}]

require 'pp'

a = [
  {"timestamp"=>1347119549, "category"=>nil},
  {"timestamp"=>1347119547, "category"=>"Monkeys"},
  {"timestamp"=>1347119543, "category"=>nil},
  {"timestamp"=>1347119542, "category"=>"Monkeys"},
  {"timestamp"=>1347119548, "category"=>"Dog"},
  {"timestamp"=>1347119544, "category"=>"Dog"}
]

pp a.group_by{|h| h['category'] ? h['category'] : h['timestamp']}.
   map{|k,v| v.sort_by{|h| -h['timestamp']}}.
   sort_by{|a| -a[0]['timestamp']}.flatten 
# >> [{"timestamp"=>1347119549, "category"=>nil},
# >>  {"timestamp"=>1347119548, "category"=>"Dog"},
# >>  {"timestamp"=>1347119544, "category"=>"Dog"},
# >>  {"timestamp"=>1347119547, "category"=>"Monkeys"},
# >>  {"timestamp"=>1347119542, "category"=>"Monkeys"},
# >>  {"timestamp"=>1347119543, "category"=>nil}]
于 2013-07-28T13:59:51.590 回答
1

它看起来有点难看,但它有效:

a = [
  {"timestamp"=>1347119549, "category"=>nil},
  {"timestamp"=>1347119547, "category"=>"Monkeys"},
  {"timestamp"=>1347119543, "category"=>nil},
  {"timestamp"=>1347119542, "category"=>"Monkeys"},
  {"timestamp"=>1347119548, "category"=>"Dog"},
  {"timestamp"=>1347119544, "category"=>"Dog"}
]
groups = a.sort_by {|h| -h['timestamp']}.group_by {|h| h['category']}
sorted = (groups.delete(nil) || []) + groups.values
sorted = sorted.sort_by{|i| i.is_a?(Hash) ? -i['timestamp'] : -i.first['timestamp']}.flatten

这为您提供以下内容sorted

[
  {"timestamp"=>1347119549, "category"=>nil},
  {"timestamp"=>1347119548, "category"=>"Dog"},
  {"timestamp"=>1347119544, "category"=>"Dog"},
  {"timestamp"=>1347119547, "category"=>"Monkeys"},
  {"timestamp"=>1347119542, "category"=>"Monkeys"},
  {"timestamp"=>1347119543, "category"=>nil}
]

我首先按 排序'timestamp',以便稍后对组进行排序。

分组后'category',我将nil类别的值移动到一个数组中。在这里,我在组为空(groups.delete(nil) || [])的情况下使用。nil

现在它可以'timestamp'再次排序,timestamp数组的timestamp第一个哈希值。

最后flatten给了我们想要的数组。

于 2013-07-28T14:28:05.877 回答
1

这里需要的技巧是分配一个唯一的组而不是 nil。您可以通过创建一个通用的 Ruby 来做到这一点Object

orig = [
  {"timestamp"=>1347119549, "category"=>nil}, 
  {"timestamp"=>1347119547, "category"=>"Monkeys"}, 
  {"timestamp"=>1347119543, "category"=>nil}, 
  {"timestamp"=>1347119542, "category"=>"Monkeys"}]

# The "tricky bit"
grouped = orig.group_by { |x| x["category"] ?  x["category"] : Object.new  }

# Sort the siblings within the groups (note negation causes reverse order)
grouped.values.each { |siblings| siblings.sort_by! { |a| -a["timestamp"] } }

# Sort the list by first (i.e. "best" sort order) timestamp in each group 
sorted_groups = grouped.sort_by { |group_id,siblings| -siblings.first["timestamp"] }

# Remove group ids and flatten the list:
result = sorted_groups.map { |group_id,siblings| siblings }.flatten
=>  [
 {"timestamp"=>1347119549, "category"=>nil}, 
 {"timestamp"=>1347119547, "category"=>"Monkeys"}, 
 {"timestamp"=>1347119542, "category"=>"Monkeys"}, 
 {"timestamp"=>1347119543, "category"=>nil}
]
于 2013-07-28T14:29:09.117 回答
1

这只需使用您尝试过的工具即可完成。

首先sort通过 tiemstamp 分配整个数组,然后使用以下方法按类别分配它们组group_by

arr = [
    {'timestamp' => 1347119549, 'category' => nil},
    {'timestamp' => 1347119547, 'category' => 'Monkeys'},
    {'timestamp' => 1347119543, 'category' => nil},
    {'timestamp' => 1347119542, 'category' => 'Monkeys'},
    {'timestamp' => 1347119541, 'category' => nil},
    {'timestamp' => 1347119548, 'category' => nil},
    {'timestamp' => 1347119545, 'category' => nil},
]

sorted = arr.sort_by { |elem| 0 - elem['timestamp'] }
groups = sorted.group_by { |elem| elem['category'] or Object.new }
sorted = groups.values.flatten

puts sorted

输出

{"timestamp"=>1347119549, "category"=>nil}
{"timestamp"=>1347119548, "category"=>nil}
{"timestamp"=>1347119547, "category"=>"Monkeys"}
{"timestamp"=>1347119542, "category"=>"Monkeys"}
{"timestamp"=>1347119545, "category"=>nil}
{"timestamp"=>1347119543, "category"=>nil}
{"timestamp"=>1347119541, "category"=>nil}

当然,您可以以可读性为代价将整个事情流水线化。

sorted = arr.sort_by { |elem| 0 - elem['timestamp'] }.group_by { |elem| elem['category'] or Object.new }.values.flatten
于 2013-07-28T14:49:16.447 回答