【问题标题】:How to sort array of strings with multiple conditions?如何对具有多个条件的字符串数组进行排序?
【发布时间】:2014-07-31 11:30:24
【问题描述】:

我有一个字符串数组,需要按多个标准(两个字符串属性)进行排序。然而,这两种排序需要以相反的方向排序。

例子:

数组必须按attribute_a按desc顺序排序,然后在该范围内 按attribute_b 升序排列。

我一直在使用 .sort_by!效果很好,但是我只是不确定如何在相反的排序方向上实现两个标准排序

【问题讨论】:

  • 你能给我们一个排序数组的例子吗?通过示例更容易准确理解您想要的内容。
  • 该数组是一个模型的输出,该模型产生一个具有多个属性的组织列表,但我需要它们按它们的“类型”按 desc 顺序排序,按它们的“名称”按 asc 顺序排序,以便排序时的示例应该输出类似这样的排序“Type z”-“name a”-“name b”-“name e”-“name f”“Type y”-“name c”-“name d”-“名称 g" 等。希望这会有所帮助
  • 我想明白你在问什么,但将来你应该编辑你的问题并给出更明确的例子。你想让别人帮助你尽可能容易。您应该将未排序的数组(原始数据)放入您的问题中,然后放入所需的输出。这样人们就可以通过输入您的输入并检查它是否输出您想要的结果来测试他们自己可能的答案。

标签: ruby-on-rails ruby arrays sorting


【解决方案1】:

如果这些属性是数据库列,可以使用:

Organization.order(attribute_a: :desc, attribute_b: :asc)

否则,将sortarray 一起使用:

数组以“元素方式”的方式进行比较;前两个不相等的元素将决定整个比较的返回值。

交换第一个元素按降序对它们进行排序:

array.sort { |x, y| [y.attribute_a, x.attribute_b] <=> [x.attribute_a, y.attribute_b] }
#                    ^                                  ^
#                    |                                  |
#                    +-------- x and y exchanged -------+

要生成your comment 中提到的列表,您可以使用group_by

<% sorted_array.group_by(&:attribute_a).each do |attr, group| %>
  <%= attr %> #=> "Type z"
  <% group.each do |item| %>
    <%= item.attribute_b %> #=> "name a", "name b", ...
  <% end %>
<% end %>

【讨论】:

    【解决方案2】:

    你可以这样做:

    sorted = a.group_by(&:attribute_a).each do |k, v| 
      v.sort_by!(&:attribute_b)
    end.sort_by(&:first).map(&:last)
    
    sorted.reverse.flatten
    

    此解决方案按attribute_a 对所有元素进行分组,按attribute_b (asc) 对每个组进行排序,并按attribute_a (asc) 对组进行排序。

    第二行将组的顺序颠倒过来(不改变组内元素的顺序),然​​后将结果展平,得到按attribute_a排序的原始列表(desc ), attribute_b (asc)

    【讨论】:

      【解决方案3】:

      试试这样的:

      a.sort! do |x, y|
          xa = get_a(x)
          ya = get_a(y)
      
          c = ya - xa
      
          return c unless c == 0
      
          xb = get_b(x)
          yb = get_b(y)
      
          return xb - yb  
      end
      

      get_aget_b 是提取 ab 参数的函数

      【讨论】:

      • 块必须返回-101
      【解决方案4】:

      这是使用排序的直接解决方案。通过否定 :

      的结果来创建相反的顺序
      sorted = some_things.sort do |x,y|
        if x.a == y.a
          x.b <=> y.b
        else
          -(x.a <=> y.a) # negate to reverse the order
        end
      end
      

      这是测试它的完整程序:

      class Thing
        attr_reader :a, :b
      
        def initialize(a, b)
          @a = a
          @b = b
        end
      end
      
      # Create some Things
      some_things = [Thing.new("alpha","zebra"), Thing.new("gamma", "yoda"), 
                     Thing.new("delta", "x-ray"), Thing.new("alpha", "yoda"), 
                     Thing.new("delta", "yoda"), Thing.new("gamma", "zebra")]
      
      sorted = some_things.sort do |x,y|
        if x.a == y.a
          x.b <=> y.b
        else
          -(x.a <=> y.a) # negate to reverse the order
        end
      end
      
      p sorted
      

      产生这个输出(插入换行符):

      [#<Thing:0x007fddca0949d0 @a="gamma", @b="yoda">, 
      #<Thing:0x007fddca0947f0 @a="gamma", @b="zebra">, 
      #<Thing:0x007fddca094958 @a="delta", @b="x-ray">, 
      #<Thing:0x007fddca094868 @a="delta", @b="yoda">, 
      #<Thing:0x007fddca0948e0 @a="alpha", @b="yoda">, 
      #<Thing:0x007fddca094a48 @a="alpha", @b="zebra">]
      

      【讨论】:

      • -(x.a &lt;=&gt; y.a) 等价于y.a &lt;=&gt; x.a
      • 哦,对了。我只是认为意图更清楚。另外,我没有意识到这个问题已经得到了回答,因为我在发布答案之前已经将窗口打开了几个小时。选择的肯定比我的更完整。
      猜你喜欢
      • 1970-01-01
      • 2013-03-09
      • 2020-06-02
      • 2020-12-25
      • 1970-01-01
      • 1970-01-01
      • 2021-12-05
      • 2011-03-10
      • 1970-01-01
      相关资源
      最近更新 更多