2016-09-20 79 views
2

我是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排序。 notsorttype可以在最后或开始。

+0

作为说明,约定认为Ruby方法和变量应该是'sort_id_order'形式。 – tadman

回答

0

一个不是很高性能的一行:

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

这使得notsort对象出现在排序数组的头。这是一个O(m * nlog(n))算法,其中n的尺寸为object,而m的尺寸为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 + n日志(n))的算法,但需要更多的存储器。

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}] 
+0

谢谢,但我希望命令由'sortIdOrder'确定。我只需将解决方案更改为: 'object.sort {| a,b | [a [:type],sortIdOrder.index(a [:id])] <=> [b [:type],sortIdOrder.index(b [:id])]}? – Decrypter

+0

是的,这是有效的。至少在这个例子中。 – davidhu2000

+0

很酷。有些情况下'type'可以是零。在这种情况下这不起作用吗? – Decrypter

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中找到的项目将被任意排序,如果你的数据集非常大,你可能需要进一步调整,以便sortIdOrder数组不对非分类项目执行

Enumerable#sort_by只需对每个元素调用一次块,然后对结果执行快速比较; 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的块形式最为有用。

+0

谢谢你的回答。如果':type'是零呢? – Decrypter

+0

如果':type'可能为零,或者除了sort和:nosort之外还有很多不同的类型,并且你想确定除了sort之外的所有东西都被分组在一起,那么最好使用'[(o [ :type] ==:sort?0:1),sortIdOrder.index(o [:id])'作为您的排序标准。将所有':sort'放在列表的前面(按照所需的排序顺序),然​​后再放入其他所有的东西(如果它们的id在'sortIdOrder'数组中不存在,可能是任意的顺序。更新答案以反映这一点。 – philomory

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(散列)创建与一个键 - 值对g[:id]=>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}} 
+0

你知道,带'index_of'调用的'sort_by'可能是去这里的路。对于较大的列表,您肯定希望将ID顺序数组转换为哈希:'Hash [array.each_with_index.to_a] .invert'可以轻松完成。 – tadman

+0

@tadman,这是'each_with_index'和'invert'的很好用法。我必须把它甩开。 –

0

也许我来晚了,但我的解决办法是:

Rails的解决方案:

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

红宝石解决方案:

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}] 
相关问题