【问题标题】:Ruby - Sort array by class typeRuby - 按类类型对数组进行排序
【发布时间】:2020-12-05 21:00:28
【问题描述】:

假设我有多个类类型的数组

array = [ 1, "1", "one", true, { one: "one" }, :one ]

我想按字母顺序按类类型对这个数组进行排序。例如:one.class => Sybmol 将在1.class => Fixnum 之后排序

我怎样才能做到这一点?

【问题讨论】:

  • 一些事情:你要求按类名字符串逆字典排序吗?你想要这个输入数组的确切输出是什么,为什么符号小于 fixnums?其次,像这样具有多种类型的数组通常是一种反模式,所以这可能是xy problem。您可能需要重新考虑您的应用程序是否应该依赖此设计。最后,请尽量避免帖子因“过于宽泛”而被关闭。

标签: arrays ruby string class sorting


【解决方案1】:

您可以使用Enumerable#sort_by,它接受一个块,您可以在接收器上调用classto_s

array.sort_by { |e| e.class.to_s }
# [{:one=>"one"}, 1, "1", "one", :one, true]

【讨论】:

  • 这段代码不仅简洁,而且还针对速度进行了相当优化。不要试图使用符号而不是字符串——它只会使它变慢,因为它需要一个额外的转换(不能将Class 转换为symbol,需要一个string 中间值)。所以使用这个(慢):array.sort_by { |e| e.class.to_s.to_sym }
【解决方案2】:

如果array 很大并且性能很重要,您可以编写以下内容。

array.group_by(&:class).sort_by { |k,_| k.to_s }.flat_map(&:last)
  #=> [{:one=>"one"},  1,    "1",  "one", :one,    true]
  #        Hash     Integer String String Symbol TrueClass 

计算步骤如下。

h = array.group_by(&:class)
  #=> {Integer=>[1], String=>["1", "one"], TrueClass=>[true],
  #    Hash=>[{:one=>"one"}], Symbol=>[:one]} 
a = h.sort_by { |k,_| k.to_s }
  #=> [[Hash, [{:one=>"one"}]], [Integer, [1]], [String, ["1", "one"]],
  #    [Symbol, [:one]], [TrueClass, [true]]] 
a.flat_map(&:last)
  #=> [{:one=>"one"}, 1, "1", "one", :one, true] 

请参阅Enumerable#group_byEnumerable#sort_byEnumerable#flat_map

narray中的元素个数,marray中的元素所代表的唯一类的个数,计算各组件的计算复杂度如下。

group_by(&:class)         : O(n)
sort_by { |k,_| k.to_s }  : O(m*log(m))
flat_map(&:last)          : O(m)

相比之下,传统排序的计算复杂度为O(n*log(n))

对于问题中给出的array的例子,

n = array.size
  #=> 6
m = array.map(&:class).uniq.size
  #=> 5

显然,在这种情况下,传统的排序方法是最快的。但是,如果n 很大而m 相对较小,则相对计算速度将由O(m*log(m))O(n*log(n)) 决定,这给我提出的方法带来了很大的优势。

请注意,这种方法适用于集合的元素e 将通过方法m 排序的任何情况,这样m(e) 的唯一值的数量与大小相比相对较小集合。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-17
    • 1970-01-01
    • 2019-05-12
    • 2020-12-14
    • 1970-01-01
    • 1970-01-01
    • 2020-10-17
    • 1970-01-01
    相关资源
    最近更新 更多