时间:2010-11-03 20:08:33

标签: ruby arrays sorting boolean

我正在使用Ruby 1.8.7。我有以下哈希数组。我需要先按布尔值排序,但这些结果必须按原始顺序排序。我基本上需要将所有真正的哈希值移到数组顶部,但保持原始顺序。

任何帮助将不胜感激!

array = [{:id => 1, :accepts => false}, 
         {:id => 2, :accepts => false}, 
         {:id => 3, :accepts => true}, 
         {:id => 4, :accepts => false}, 
         {:id => 5, :accepts => true}]

sorted = array.sort do |x, y|
  if x[:accepts] == y[:accepts]
    0
  elsif x[:accepts] == true
    -1
  elsif x[:accepts] == false
    1
  end
end

这种我得到的结果:

5 - 真实 3 - 真实 2 - 假
4 - 假
1 - 假

我需要它来产生:

3 - 真实 5 - 真实 1 - 假
2 - 假
4 - 假

7 个答案:

答案 0 :(得分:14)

使用sort_by来做这些事情,而不是sort

array.sort_by {|h| [h[:accepts] ? 0 : 1,h[:id]]}

答案 1 :(得分:8)

这就是工作:

array.sort{|a,b| (a[:accepts] == b[:accepts]) ? ((a[:id] < b[:id]) ? -1 : 1) : (a[:accepts] ? -1 : 1)}

答案 2 :(得分:1)

答案 3 :(得分:1)

好吧,根据您的问题,我推断您确实希望按:accepts值对结果进行分组,并将两个结果集合并回一个数组。我的解决办法就是:

array.select {|where| where[:accepts] } | array.reject {|where| where[:accepts] }
# => [{:accepts=>true, :id=>3},
#     {:accepts=>true, :id=>5},
#     {:accepts=>false, :id=>1},
#     {:accepts=>false, :id=>2},
#     {:accepts=>false, :id=>4}]

这将维持原始订单,而不会在:id键上隐含任何排序。这意味着您不需要辅助键来保留顺序,并且无论传输的数据如何,您都可以保留结果的顺序。

这可能也很有用(也许正是您进一步评估所需要的):

array.group_by {|where| where[:accepts] }
# => {false=>[{:accepts=>false, :id=>1},
#             {:accepts=>false, :id=>2},
#             {:accepts=>false, :id=>4}],
#      true=>[{:accepts=>true, :id=>3},
#             {:accepts=>true, :id=>5}]}

同样,没有人工排序...... group_by是1.8.7中的新内容。

PS:如果您不希望第一个代码段从阵列中删除重复项,请使用plus运算符替换bar运算符。 “|”根据{{​​3}}(union)合并两个集合,而“+”连接两个集合(结果实际上不是集合而是普通数组)。

答案 4 :(得分:0)

如果:id相等,您可以在:accepts键上添加额外的检查,如下所示:

array = [{:id => 1, :accepts => false}, 
    {:id => 2, :accepts => false}, 
    {:id => 3, :accepts => true}, 
    {:id => 4, :accepts => false}, 
    {:id => 5, :accepts => true}]

sorted = array.sort do |x, y|
  if x[:accepts] == y[:accepts]
    if x[:id] == y[:id]
      0
    elsif x[:id] > y[:id]
      1
    elsif x[:id] < y[:id]
      -1
    end
  elsif x[:accepts] == true
    -1
  elsif x[:accepts] == false
    1
  end
end

答案 5 :(得分:0)

a.sort_by { |x| (x[:accepts] ? 0 : 99999) + x[:id] }

更新:显然,这需要x[:id].respond_to? "+",并且相对于常量,其范围也有限制。

然而,这是最短且可能是最快的答案,如果也显然是最值得怀疑的。

真正重要的一课是,它说明一个人应该超越Array(或其他),并检查Enumerable是否在(your object).class.ancestors。这些问题和他们的观众经常回答“我接下来应该学习什么关于Ruby,我怀疑还有其他方法”。

无论这是一种好的排序方式(不可否认,这是有问题的),这个答案建议#sort_by,只是找到#sort_by的文档(它不在数组中)将为初学者教授一个小而重要的课程。

答案 6 :(得分:0)

这是因为Ruby 1.8.7中的排序不稳定

您需要做的就是让排序块不返回0

sorted = array.sort do |x, y|
  if x[:accepts] == y[:accepts]
    x[:id] <=> y[:id]  # not 0
  elsif x[:accepts]
    -1
  else
    1
  end
end

(无需明确将布尔值与truefalse

进行比较