11

ハッシュの配列があるとすれば、下の画像のように (ruby を使用して) それらを (created_at 値を使用して) Podium スタイルにソートするにはどうすればよいでしょうか?

[
  { created_at: "DATETIME", src: "..." },
  { created_at: "DATETIME", src: "..." },
  { created_at: "DATETIME", src: "..." },
  { created_at: "DATETIME", src: "..." }
]

ここに画像の説明を入力

4

16 に答える 16

8

arr.sort_by{|a| a['created_at']}.inject([]){ |r, e| r.reverse << e }

楽しい問題!

于 2013-11-11T02:40:44.237 に答える
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
于 2013-10-30T17:06:23.333 に答える
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}]
于 2013-11-11T10:34:53.163 に答える
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}]
于 2013-10-30T17:18:48.447 に答える
2

さらに別の方法

arr.sort_by { |h| h[:created_at] }.sort_by.with_index { |_,i| i.odd? ? -i : i }
于 2014-03-21T23:49:02.703 に答える
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
于 2013-10-30T17:16:54.843 に答える
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">

楽しい問題。

于 2013-11-05T23:32:07.110 に答える
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
于 2013-11-06T06:31:37.010 に答える
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

編集

次の 2 つに対して、このソリューションのベンチマークを行いました。

配列のすべての要素のチェックに基づく実装

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)

最終的には、焦点を当てたいところに行き着きます。

  • 「連続リバース」実装 (IMHO) は非常に洗練されていますが、非常に遅くなります。
  • 一方、他の 2 つの実装は同様の速度のようです (配列の長さに基づく実装の方がわずかに優れています)。
于 2013-11-10T18:32:06.803 に答える
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
于 2013-10-31T16:35:24.627 に答える