我是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
}]
如您所见,数组基于id
按sortIdOrder
排序。 notsort
type
可以在结尾或开始。
答案 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
的大小为object
,m
的大小为sortIdOrder
。当object
和sortIdOrder
很小时,这会更快。
大型阵列的性能更高
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}]