对数组中的特定对象进行排序

时间:2016-09-20 02:15:39

标签: ruby

我是Ruby新手,希望只对我的收藏中的某些项目进行排序。 例如,如果我有以下数组。我只想对包含属性type: 'sort'

的对象进行排序
   object = [{
            type: 'sort',
            id: 3
        }, {
            type: 'notsort',
            id: 4
        }, {
            type: 'sort',
            id: 1
        }, {
            type: 'sort',
            id: 0
        }
    ]

我需要将订单直接映射到下面的id地图。

sortIdOrder = [0, 1, 3]

最终结果如下:

object = [{
    type: 'notsort',
    id: 4
}, {
    type: 'sort',
    id: 0
},{
    type: 'sort',
    id: 1
}, {
    type: 'sort',
    id: 3
}]

如您所见,数组基于idsortIdOrder排序。 notsort type可以在结尾或开始。

5 个答案:

答案 0 :(得分:3)

排序可能很昂贵,所以不应该在知道所需的顺序时进行排序,就像在这里一样。

我认为价值:id是唯一的,因为如果不是这个问题就没有意义。

首先将哈希分为要排序的哈希值和其余的哈希值。

sortees, nonsortees = object.partition { |h| h[:type] == 'sort' }
  #=> [[{:type=>"sort", :id=>3}, {:type=>"sort", :id=>1}, {:type=>"sort", :id=>0}],
  #    [{:type=>"notsort", :id=>4}]] 

所以

sortees
  #=> [{:type=>"sort", :id=>3}, {:type=>"sort", :id=>1}, {:type=>"sort", :id=>0}]
nonsortees
  #=> [{:type=>"notsort", :id=>4}] 

我将sortees的元素按所需顺序放置,然后将该数组与nonsortees连接起来,放入最后不要排序的哈希值。

我通过为sortees的每个元素g[:id]=>g(哈希)创建一个带有一个键值对g的哈希来命令sortees的元素。这允许我使用Hash#values_at以指定的顺序提取所需的哈希值。

sortees.each_with_object({}) { |g,h| h[g[:id]] = g }.
        values_at(*sortIdOrder).
        concat(nonsortees)
  #=> [{:type=>"sort", :id=>0}, {:type=>"sort", :id=>1}, {:type=>"sort", :id=>3},
  #    {:type=>"notsort", :id=>4}]

请注意

sortees.each_with_object({}) { |g,h| h[g[:id]] = g }
  #=> {3=>{:type=>"sort", :id=>3}, 1=>{:type=>"sort", :id=>1},
  #    0=>{:type=>"sort", :id=>0}} 

答案 1 :(得分:0)

您可以sort使用按:type排序的块,然后使用:id

object.sort {|a, b| [a[:type], a[:id]] <=> [b[:type], b[:id]] }

[{:type=>"notsort", :id=>4}, 
 {:type=>"sort", :id=>0}, 
 {:type=>"sort", :id=>1}, 
 {:type=>"sort", :id=>3}]

答案 2 :(得分:0)

我会选择这样的事情:

object.sort_by do |o|
  [
    (o[:type] == :sort) ? 0 : 1,
    sortIdOrder.index(o[:id])
  ]
end

当按数组排序时,你基本上按第一个元素排序,除非它们是相同的,在这种情况下你按第二个元素排序等。在上面的代码中,(o[:type] == :sort) ? 0 : 1确保首先是:sort类型的所有内容,以及之后的所有内容,即使类型为nil,或5或您喜欢的任何内容。 sortIdOrder.index(o[:id])字词可以确保事情按照您的喜好排序(虽然:id没有:id,但sortIdOrder中找不到Enumerable#sort_by的项目会被任意排序。如果你的数据集非常大,您可能希望进一步调整此值,以便不对非排序项执行sortIdOrder数组。

Enumerable#sort只需为每个元素调用一次块,然后对结果进行快速比较; irb(main):015:0> ary = %w{9 8 7 6 5 4 3 2 1} => ["9", "8", "7", "6", "5", "4", "3", "2", "1"] irb(main):016:0> a = 0; ary.sort_by {|x| puts x; a+=1; x.to_i }; puts "Total: #{a}" 9 8 7 6 5 4 3 2 1 Total: 9 => nil irb(main):017:0> a = 0; ary.sort {|x,y| puts "#{x},#{y}"; a+=1; x.to_i <=> y.to_i }; puts "Total: #{a}" 9,5 5,1 8,5 2,5 7,5 3,5 6,5 4,5 6,8 8,9 7,8 6,7 1,3 3,4 2,3 1,2 Total: 16 => nil 必须在元素对上调用块,这意味着它更经常被调用:

sort_by

在这些情况下,它确实不是很重要,因为哈希访问速度仍然很快(尽管sort_by 仍然更清晰),但是在计算要排序的属性的情况下即使价格相当昂贵,sort可能会快得多。如果比较逻辑本身很复杂,hashTable = (node**)malloc(size * sizeof(node*) 的块形式最有用。

答案 3 :(得分:0)

性能不高的单线:

object.sort_by{|o| sortIdOrder.index(o[:id]) || -1}

这使notsort个对象出现在排序数组的头部。它是O(m * nlog(n))算法,其中n的大小为objectm的大小为sortIdOrder。当objectsortIdOrder很小时,这会更快。

大型阵列的性能更高

order = sortIdOrder.each.with_index.with_object(Hash.new(-1)) {|(id, index), h| h[id] = index}

object.sort_by{|o| order[o[:id]]}

这是一个O(m + nlog(n))算法但需要更多内存。

答案 4 :(得分:0)

也许我迟到了,但我的解决方案是:

Rails解决方案:

object.partition { |hash| hash[:id].in?(sortIdOrder) }.flatten.reverse

Ruby解决方案:

object.partition { |hash| sortIdOrder.include? hash[:id] }.flatten.reverse

结果两者都给出了这个:

=> [{:type=>"notsort", :id=>4},
     {:type=>"sort", :id=>0},
     {:type=>"sort", :id=>1},
     {:type=>"sort", :id=>3}]