2009-12-23 216 views
0

用户已经定义了数组中列的顺序。在ruby中对数组进行排序

order = [:col1, :col2, :col3] 

由于用户定义的列顺序表的状态已经改变,当前的列清单

cols = [:col1, :col4, :col3, :col5] 

在给定的顺序的cols需要排序。在这种情况下,排序的列可能看起来像这两种情况之一。

[:col2, :col3, :col4, :col5] 
[:col2, :col3, :col5, :col4] 

这是我的代码让它工作。想知道是否有更好的方法。

#get rid of :col2 since it is not present in the cols listing 
sanitized_order = order - (order - cols) 

sorted_cols = sanitized_order + (cols - sanitized_order) 
+0

我对规范有点困惑。你怎么知道:col4和col5不在列表的开头(例如),因为它们不是排序的一部分?或者是“如果他们不在排序中,那么他们到最后”的规则? – 2009-12-23 14:59:47

+0

如果列没有在顺序列表中定义,那么我会要求将它们放在顺序列中提到的列之后。基本上说:低优先级的col4和col5。 – Roger 2009-12-23 15:05:19

回答

2

你是什么意思?你已经很轻松地完成了你的任务。

1)这就像你的,但有一条可读的线。

#order & cols -> provides unique items found in both 
#cols - order -> provides columns that are in cols but not order 
sorted_cols = (order & cols) + (cols - order) 

2) 这是一种方式,读起来更像是一本书,所以有人能跟上一行一行地看逻辑,而不是找出表中的差异:

order = [:col1, :col2, :col3] 
cols = [:col1, :col4, :col3, :col5] 

sanitized_order = [] 

order.each do |column| 
    if cols.include?(column) then 
    sanitized_order << column 
    cols.delete(column) 
    end 
end 

cols.each do |remainingcolumn| 
    sanitized_order << remainingcolumn 
end 

puts sanitized_order 
0

这里的另一个罗嗦的方式来做到这一点:

order = [:col1, :col2, :col3] 
cols = [:col3, :col2, :col5, :col4] 
sorted_order = cols.sort_by do |c| 
    if order.index(c) 
    [1, order.index(c)] 
    else 
    [2, cols.index(c)] 
    end 
end 
p sorted_order # => [:col2, :col3, :col5, :col4] 

这是它的工作原理。 sort_by将数组的元素返回到块;该块应该返回一些可比较的数据(技术上说,对< =>运算符做出响应)。 sort_by使用由块返回的结果< =>运营商来决定什么样的顺序排列应该英寸

的< =>(飞船)运算符,如你所知,是一个二元运算符取两个元素的和b。如果一个< b,它返回-1。如果a == b,则返回0.如果a> b,则返回+1。

数组以一种并不意外的方式回应给< =>运算符。左数组的元素依次与右数组的元素进行比较,从索引0开始并逐渐增加。如果a [i] < => b [i]为!= 0,则返回该结果,但如果结果为0,则检查下一个元素。如果比较的最后一对元素是0(等于)并且数组的大小相同,则数组与Array是相等的。 < =>返回0,否则认为较长的数组较大(然而,该示例总是返回相同大小的数组)。

所以,例如:

[2, 1] <=> [2, 2] == -1 
[2, 2] <=> [2, 2] == 0 
[2, 3] <=> [2, 2] == +1 
[1, 2] <=> [2, 1] == +1 

所以,一个内部sort_by,我们可以使用阵列中的,以指示伯,仲,叔等排序顺序的元素。 a [0]是主要排序顺序,[1]是次要排序顺序,依此类推。

客户指定的所有列都应该排在第一位。因此,对于每一列,请按照客户指定的顺序(order)查找其索引。如果它返回一个数字,那么我们知道客户指定了该列,并且我们知道它在客户指定列表中的索引。主要排序顺序为1,因为我们希望客户指定的列先到达;次级排序顺序是索引,因为这给了我们客户指定列的顺序。

如果我们在顺序数组中找不到列(即order.index(c)返回nil),那么我们将2作为主排序顺序,并将主列列表中的索引(cols )作为次要排序顺序。通过这种方式,客户没有指定的所有列都将是最后一个,但按照它们在激光列列表中指定的顺序排列。

+0

很酷。这将工作。不过,我认为发生的事情并不那么明显。 – Roger 2009-12-28 04:36:00

+0

我添加了一个解释。我希望有所帮助。 – 2009-12-29 01:14:45