鉴于我有哈希数组,如何将它们(使用ruby)排序为讲台样式(使用其created_at值),如下图所示?
[
{ created_at: "DATETIME", src: "..." },
{ created_at: "DATETIME", src: "..." },
{ created_at: "DATETIME", src: "..." },
{ created_at: "DATETIME", src: "..." }
]
答案 0 :(得分:8)
arr.sort_by{|a| a['created_at']}.inject([]){ |r, e| r.reverse << e }
有趣的问题!
答案 1 :(得分:6)
我相信你可以进一步压缩这个,但这样的事情可以解决这个问题:
# Your initial array
item_array = [{...}]
count = 0
# Sort it first, then stagger results to each side of the array
podium_sorted = item_array.sort_by{|a| a['created_at']}.inject([]) do |arr, item|
count += 1
count % 2 == 0 ? arr.unshift(item) : arr.push(item)
end
答案 2 :(得分:5)
如果你不反对使用完全心理解决方案,我非常喜欢这个:
zipped = (1..5).zip [:push, :unshift].cycle
# => [[1, :push], [2, :unshift], [3, :push], [4, :unshift], [5, :push]]
[].tap { |result| zipped.each { |val, op| result.send op, val } }
# => [4, 2, 1, 3, 5]
module Enumerable
def to_podium
[].tap { |r| (zip [:push, :unshift].cycle).each { |v, o| r.send o, v } }
end
end
(1..10).to_podium
# => [10, 8, 6, 4, 2, 1, 3, 5, 7, 9]
并在行动中展示:
test_input = (1..5).map { |i| { created_at: i, some_val: rand(100) } }.shuffle
# => [{:created_at=>3, :some_val=>69},
# {:created_at=>5, :some_val=>15},
# {:created_at=>2, :some_val=>89},
# {:created_at=>4, :some_val=>77},
# {:created_at=>1, :some_val=>54}]
test_input.sort_by { |e| e[:created_at] }.to_podium
# => [{:created_at=>4, :some_val=>77},
# {:created_at=>2, :some_val=>89},
# {:created_at=>1, :some_val=>54},
# {:created_at=>3, :some_val=>69},
# {:created_at=>5, :some_val=>15}]
答案 3 :(得分:3)
def podium_sort(array)
array.sort_by{|h| h[:created_at]}.each_with_index.inject([]) do |out, (item, index)|
index.odd? ? out.unshift(item) : out.push(item)
end
end
podium_sort((1..10).map { |value| {created_at: Time.now - rand(value..100).minutes } })
=> [{:created_at=>2013-10-30 18:03:54 -0400},
{:created_at=>2013-10-30 17:58:54 -0400},
{:created_at=>2013-10-30 17:44:54 -0400},
{:created_at=>2013-10-30 17:18:54 -0400},
{:created_at=>2013-10-30 16:54:54 -0400},
{:created_at=>2013-10-30 16:48:54 -0400},
{:created_at=>2013-10-30 16:57:54 -0400},
{:created_at=>2013-10-30 17:37:54 -0400},
{:created_at=>2013-10-30 17:44:54 -0400},
{:created_at=>2013-10-30 18:00:54 -0400}]
答案 4 :(得分:2)
使用Enumerable#partition
的替代解决方案:
items = [5,1,2,4,3].sort # use any sort method that is relevant
odd, even = items.each_with_index.partition{ |item,index| index.odd? }
podium = even.reverse.push(*odd).map(&:first) # &:first to remove index
效率可能略低(必须构建中间数组),但更紧凑。
此外,一些人在这里公开的解决方案也可以更紧凑地重写:
items.sort.each_with_index.inject([]) do |podium,(item,index)|
index.odd? ? podium.unshift(item) : podium.push(item)
end
这可能是Enumerable
或您选择的任何可枚举类的一个很好的扩展:
module Enumerable
def podium(&block)
items = block_given? ? sort : sort_by(&block)
items.each_with_index.inject([]) do |podium,(item,index)|
index.odd? ? podium.unshift(item) : podium.push(item)
end
end
end
答案 5 :(得分:2)
如果你想要一个没有两种解决方案的解决方案:
arr = [ { :created_at => ... }, { :created_at => ... }, ... ]
size = arr.count
poss = Array.new(size) { |i| i%2 == 0 ? size-(i/2+1) : i/2 }
final = [-1]*size
然后,将插入排序应用于非线性映射poss
只是一个简单的问题。所以你会做的事情如下:
arr.each do |val|
poss.each_with_index do |pos, pos_index|
if final[pos] == -1
final[pos] = val
break
elsif final[pos][:created_at] < val[:created_at]
tmp_val = final[pos]
final[pos] = val
poss[pos_index+1..size].each do |new_pos|
if final[new_pos] == -1
final[new_pos] = tmp_val
break
elsif final[new_pos][:created_at] < tmp_val[:created_at]
tmp2_val = final[new_pos]
final[new_pos] = tmp_val
tmp_val = tmp2_val
end
end
break
end
end
end
非常简单地说,这只是插入排序算法的一种实现,而不是映射到线性线,我们映射到poss。
答案 6 :(得分:2)
又一种方式
arr.sort_by { |h| h[:created_at] }.sort_by.with_index { |_,i| i.odd? ? -i : i }
答案 7 :(得分:1)
# Initializing variable to store the output
podium_sorted = []
# Assuming sorting has to be in descending order of created_at
#(If you want it in ascending the just remove `reverse` from the below line)
sorted_array = input_array.sort_by { |record| record[:created_at] }.reverse
sorted_array.each_with_index do |record, index|
index.even? ? podium_sorted << record : podium_sorted = [record] + podium_sorted
end
答案 8 :(得分:1)
这是我使用Ruby的OpenStruct和Mixin提出的解决方案。
FWIW我在你的初始哈希中添加了一个名为given_order的键,用于打印输出上的视觉提示。显然,对于最终问题,这是不必要的。
require 'ostruct'
# compose a lightweight class and make it comparable
class SortableSeed < OpenStruct
include Comparable
def <=>(other)
created_at <=> other.created_at
end
end
# initial seed. src
seed = [
{ created_at: Time.now + 180, src: "...", given_order: "1" },
{ created_at: Time.now + 60, src: "...", given_order: "2" },
{ created_at: Time.now + 240, src: "...", given_order: "3" },
{ created_at: Time.now, src: "...", given_order: "4" },
{ created_at: Time.now + 320, src: "...", given_order: "5" }
]
# show inital arrangement
puts "Initial Seed (random order)\n"
puts seed
puts "\n"
# Create our structs from seed
structs = seed.map {|struct| SortableSeed.new(struct)}
# sort and out print them
puts "Podium Sort (by created_at)\n"
structs.sort.map {|struct| puts struct.inspect}
输出:
# Initial Seed (random order)
{:created_at=>2013-11-05 17:30:22 -0600, :src=>"...", :given_order=>"1"}
{:created_at=>2013-11-05 17:28:22 -0600, :src=>"...", :given_order=>"2"}
{:created_at=>2013-11-05 17:31:22 -0600, :src=>"...", :given_order=>"3"}
{:created_at=>2013-11-05 17:27:22 -0600, :src=>"...", :given_order=>"4"}
{:created_at=>2013-11-05 17:32:42 -0600, :src=>"...", :given_order=>"5"}
# Podium Sort (by created_at)
#<SortableSeed created_at=2013-11-05 17:27:22 -0600, src="...", given_order="4">
#<SortableSeed created_at=2013-11-05 17:28:22 -0600, src="...", given_order="2">
#<SortableSeed created_at=2013-11-05 17:30:22 -0600, src="...", given_order="1">
#<SortableSeed created_at=2013-11-05 17:31:22 -0600, src="...", given_order="3">
#<SortableSeed created_at=2013-11-05 17:32:42 -0600, src="...", given_order="5">
有趣的问题。
答案 9 :(得分:1)
def podium_sort arr
arr.sort_by {|h| h[:created_at]}.map.with_index {|e,i|
i.odd? ? [-i,e] : [i,e]}.sort.map(&:last)
end
arr = [
{:created_at=>2013-11-05 22:20:59 -0800},
{:created_at=>2013-11-05 22:22:07 -0800},
{:created_at=>2013-11-05 22:21:31 -0800},
{:created_at=>2013-11-05 22:22:04 -0800},
{:created_at=>2013-11-05 22:21:06 -0800},
{:created_at=>2013-11-05 22:21:10 -0800},
{:created_at=>2013-11-05 22:20:44 -0800},
{:created_at=>2013-11-05 22:20:52 -0800},
{:created_at=>2013-11-05 22:22:00 -0800},
{:created_at=>2013-11-05 22:21:50 -0800},
{:created_at=>2013-11-05 22:21:15 -0800}
]
podium_sort(arr) #=> [
{:created_at=>2013-11-05 22:22:04 -0800},
{:created_at=>2013-11-05 22:21:50 -0800},
{:created_at=>2013-11-05 22:21:15 -0800},
{:created_at=>2013-11-05 22:21:06 -0800},
{:created_at=>2013-11-05 22:20:52 -0800},
{:created_at=>2013-11-05 22:20:44 -0800},
{:created_at=>2013-11-05 22:20:59 -0800},
{:created_at=>2013-11-05 22:21:10 -0800},
{:created_at=>2013-11-05 22:21:31 -0800},
{:created_at=>2013-11-05 22:22:00 -0800},
{:created_at=>2013-11-05 22:22:07 -0800}
]
编辑:还有一个:
def sel(a,t) a.select {|e| t = !t} end
def podium_sort(a)
sel(a.sort!,true).reverse + sel(a,false)
end
答案 10 :(得分:1)
对物品进行分类,然后从中间开出领奖台。
def podium_sort(items)
sorted = items.sort_by{|h|h[:created_at]}
sorted.each_slice(2).reduce([]) { |podium, pair|
[pair[1]] + podium + [pair[0]]
}.compact
end
更多变体,使用each_slice(2)
:
对物品进行分类,在讲台的左右两侧构建,然后合并。
def podium_sort(items)
left = []
right = []
sorted = items.sort_by{|h|h[:created_at]}
sorted.each_slice(2){|a,b| left.unshift(b); right << a}
(left.compact + right)
end
对项目进行排序,将成对的列转换为行,然后合并。
def podium_sort(items)
sorted = items.sort_by{|h|h[:created_at]}
sorted += [nil] if items.length.odd?
right, left = sorted.each_slice(2).to_a.transpose
(left.compact.reverse + right)
end
答案 11 :(得分:1)
让数组按created_at属性排序,我们可以提供类似
的方法def podium_sort(array)
result = []
l = array.length / 2 + 1
l.times do |i|
result.push(array[2*i])
result.unshift(array[2*i+1])
end
result.compact
end
修改
我针对以下两个方案对此解决方案进行了基准测试:
基于检查数组的每个元素的实现
def pod_if(ar)
count = 0
ar.sort_by{|a| a[:created_at]}.inject([]) { |arr, item|
count += 1
count % 2 == 0 ? arr.unshift(item) : arr.push(item);
}
end
和具有连续反转的实现(@bonzofenix)。 (最优雅,但相当昂贵)
def pod_reverse(arr)
arr.sort_by{|a| a['created_at']}.inject([]){ |r, e| r.reverse << e }
end
对于100个哈希的数组a,基准是:
Benchmark.bm do |x|
x.report('zig_zag') { 1000000.times { podium_sort a } }
x.report('if_based') { 1000000.times { pod_if a } }
x.report('reverse') { 1000000.times { pod_reverse a } }
end
和结果
user system total real
zig_zag 89.090000 0.490000 89.580000 (121.833205)
if_based 97.250000 0.230000 97.480000 (123.692612)
reverse 207.050000 0.610000 207.660000 (267.401497)
所以最终它们最终都集中在我们想要关注的地方,
答案 12 :(得分:1)
一衬垫:
((0...A.length).select(&:odd?).reverse + (0...A.length).select(&:even?)).collect { |p| A.sort_by { |i| i[:created_at] }[p] }
或者,将其分解为更易阅读的形式:
podium = ((0...A.length).select(&:odd?).reverse + (0...A.length).select(&:even?)
sorted_array = A.sort_by { |i| i[:created_at] }
podium.collect { |p| sorted_array[p] }
答案 13 :(得分:0)
正常排序数组,然后运行以下代码:
result = []
a.each.with_index do |x, i|
i.even? ? result.push(x) : result.unshift(x)
end
另一种方法:
a.push(nil) if a.size.odd?
a = a.each_slice(2).to_a.transpose
p (a.first.reverse + a.last).compact
答案 14 :(得分:0)
它基于(-1)** k的符号变化。但有2种排序:(
arr = [....]
k = - 1;
arr.sort_by{|item| item[:created_at]}.sort_by{|item| k *= -1; k*item[:created_at].to_time.to_i}
答案 15 :(得分:0)
toggle = true
array.sort_by{|a| a['created_at']}.inject([]) do |r, e|
toggle ? r.push(e) : r.unshift(e)
toggle = !toggle
r
end