Ruby 按布尔值和数字排序

Posted

技术标签:

【中文标题】Ruby 按布尔值和数字排序【英文标题】:Ruby sort by boolean and number 【发布时间】:2011-05-04 17:19:13 【问题描述】:

我使用的是 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 - 错误

【问题讨论】:

【参考方案1】:
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]
      x[:accepts] ? -1 : 1
  else
      x[:id] <=> y[:id]
  end
end

puts sorted

如果您愿意,也可以使用!= 而不是^

【讨论】:

【参考方案2】:

这样就可以了:

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

【讨论】:

宾果游戏!感谢一百万菲利普! 我不喜欢这个解决方案,因为它不保留作者提到的原始订单作为要求。相反,它暗示 :id 已被订购并误用它作为辅助键。 也许这是一个要求集,因为他习惯了另一种语言。 Ruby Array 类不知道可以更改元素位置的操作。恕我直言,在使用 Ruby 时坚持内置函数很重要,因为它可以节省性能。 (尤其是 MRI。)但是代码并不意味着预购,用 irb 试试吧。 @hurikhan77 哦,我明白你的意思了。尽管如此,它还是相当简单的代码。 @Philip 在了解 OP 可能不想排序但真正拆分和合并之后,我有一个想法解决这个问题而不进行排序。 :id 似乎是一个辅助键,仅此而已。在下面查看我的答案(想知道为什么它在没有给出理由的情况下被否决)。【参考方案3】:

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

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

【讨论】:

【参考方案4】:
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 (它不在数组中)将教一个小但对初学者来说很重要。

【讨论】:

这是一种非常糟糕和愚蠢的答案,看起来很聪明。不适合初学者在学习新语言的第一步寻求帮助 - 特别是在没有任何解释的情况下。 这个被否决的答案与@glenn mcdonald 的被投赞成票的答案有什么不同?两个答案都可以解释一下,这是真的,格伦的要好一点,但这个也没有那么不好。 “非常糟糕和愚蠢”不是一个非常协作的评论,但客观地说,我认为这个评论有三个可识别的缺陷,使其成为一个不太理想的建议。最明显的是,它假设 id 不会高于 99999。现在或以后很容易出错。其次,像 99999 这样的魔法值通常是清晰度和理解力的敌人,因此也是可维护性的敌人。第三,这个版本使用了加法,这在功能上是不相关的,如果 id 后来变成字符串,或者负数或其他东西,它就会中断。 如果这种方法具有补偿性优点,或者替代方案具有复杂的约束条件,则可以容忍任何这些事情。但是做一个包含两个元素的数组而不是添加两个数字就更清楚了。那有意义吗? (为了清楚起见,我没有对此投反对票,我只是想解释一下。) @glenn 实际上我写了“有点”,但点了。 +1...由于添加了解释,投票发生了变化【参考方案5】:

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

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

【讨论】:

@Nakilon,在我的机器上并使用 MRI 1.8.7,格伦的代码花费的时间不到你代码的一半。 我并不是说sort 没有比sort_by 快的情况,但我自己从未遇到过。通常sort_by 明显更快。更重要的是,编写一个产生一元排序值的函数总是比一堆二进制比较案例更清晰、更清晰。就个人而言,我保留sort 用于根据比较的配对特征实际需要执行不同逻辑的情况。就像如果我需要比较字符串,如果它们都是数字,或者如果它们都是日期,或者按字符串比较......【参考方案6】:

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

http://redmine.ruby-lang.org/issues/show/1089 http://en.wikipedia.org/wiki/Stable_sort#Stability

您需要做的就是让您的排序块不返回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 进行比较)

【讨论】:

【参考方案7】:

好吧,从您的问题中,我推断您确实想按 :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:如果您不希望第一个代码 sn-p 从数组中删除重复项,请将 bar 运算符替换为 plus 运算符。 “|”根据theory of sets(联合)合并两个集合,而“+”连接两个集合(结果不是真正的集合,而是一个普通数组)。

【讨论】:

以上是关于Ruby 按布尔值和数字排序的主要内容,如果未能解决你的问题,请参考以下文章

类型-graphql。字符串、布尔值和数字的联合类型失败

MySQL 按日期排序和布尔优先级:数字到日期的怪异

函数不返回正确的布尔值

数组列表按布尔值排序,然后按日期 JavaScript / TypeScript

编辑布尔值和运算符

首先按布尔列对数组进行排序,然后按字符串列排序