我想按几个动态条件对散列数组进行排序。假设我有这个数组

persons = [
  {
    id: 1,
    first_name: "Bill",
    last_name: "Zamora",
    age: 37
  },
  {
    id: 2,
    first_name: "Alexia",
    last_name: "Reyes",
    age: 70
  },
  {
    id: 3,
    first_name: "Anthony",
    last_name: "Nelson",
    age: 25
  }
]

我知道您可以使用以下代码轻松地按多个条件对数组进行排序
persons.sort_by!{ |p| [p[:age], p[:first_name]] }

但是,在本例中,数组排序所依据的字段的编号和顺序是硬编码的。在我的例子中,这是在运行时动态确定的。所以我不知道数组要排序多少个字段,也不知道哪些字段按哪个顺序排序。
我正在寻找一个优雅的解决方案来使用一个我以前不知道的配置对象来排序我的数组。这样的配置可能如下所示:
sort_settings = [
  {
    field: "first_name",
    order: "asc"
  },
  {
    field: "age",
    order: "desc"
  }
]

我非常感谢你的帮助!

最佳答案

使用sort_by按desc顺序对字符串排序是相当困难的,最好使用“lower level”sort方法,该方法使用<=>运算符按指定的比较器排序。一个快速的解决方案如下:

persons.sort do |a, b|
  comparator = 0

  sort_settings.each do |s|
    a_field = a[s[:field].to_sym]
    b_field = b[s[:field].to_sym]

    comparator = a_field <=> b_field

    comparator = -comparator if s[:order] == "desc"

    break unless comparator == 0
  end

  comparator
end

块必须实现A和B之间的比较,当A跟B在一起时返回-1,当A和B相等时返回0,或者当B跟A在一起时返回+1。
因此,我们遍历sort_settings并使用<=>比较指定的字段,它返回10-1。如果指定的顺序是desc,则我们反转该值。如果comparator返回不同于零的值,我们不需要继续迭代。

09-30 22:35
查看更多