1

如何对数组进行排序,如下所示:

[["9213533",
  {:length=>"9213533",
   :units=>["Meters", "Feet", "Yards"],
   :frequency=>3}],
 [nil, 
  {:length=>nil, :units=>["Feet"], :frequency=>1}],
 ["5951975", 
  {:length=>"5951975", :units=>["Yards"], :frequency=>1}],
 ["9100799", 
  {:length=>"9100799", :units=>["Feet"], :frequency=>1}]]

我想对其进行排序,以便数组数组的第一个元素为 nil 来到最后一个位置,如下所示(排序):

[["9213533",
      {:length=>"9213533",
       :units=>["Meters", "Feet", "Yards"],
       :frequency=>3}],
     ["5951975", 
      {:length=>"5951975", :units=>["Yards"], :frequency=>1}],
     ["9100799", 
      {:length=>"9100799", :units=>["Feet"], :frequency=>1}]],
     [nil, 
      {:length=>nil, :units=>["Feet"], :frequency=>1}]

我尝试过按方法排序(arr 是我的数组):

arr.sort_by{|a,b| b[:length] unless a.nil?}

得到了这个例外:

ArgumentError: comparison of NilClass with String failed
from (pry):395:in `sort_by
4

3 回答 3

6
arr2 = arr.sort_by { |k, h| k ? [0, h[:length].to_i] : [1] }

或者:

arr2 = arr.sort_by { |k, h| k ? h[:length].to_i : Float::INFINITY }

[编辑] 这就是我以为您从代码中提出的问题,但实际上您要求将第一个nil放在最后,这是完全不同的事情:

idx = arr.index { |k, h| k.nil? }
arr2 = idx ? [arr[0...idx] + arr[idx+1..-1], arr[idx]] : [arr, nil]
于 2013-06-26T13:27:44.883 回答
3

所有基于sortor sort_byare wrong的早期答案,因为它们修改了非零值的顺序。请注意,询问者只希望将 nil 值下沉到数组的末尾,同时保留所有其他元素的原始顺序

这是正确完成的方法。

简洁版本

class Array
  def sink_nils!
    self.replace self.partition { |value| value[0] != nil }.flatten(1)
  end
end

arr.sink_nils!

此代码转换arr为与请求者请求的数组相等的数组。

以更易读的形式相同的代码,解释

class Array
  def sink_nils!
    # Move nil-containing elements into a separate array
    result = self.partition { |value| value[0] != nil }

    # Glue two arrays into a single one
    result.flatten!(1)

    # Swap the original array with the result
    self.replace result
  end
end

arr.sink_nils!

这就是发生的事情。

  • .partition根据块中提供的条件将数组拆分为两个数组。我们使用一个value[0] != nil条件将包含 nil 的项目与不包含 nil 的项目分开,同时保留它们的原始顺序。
  • .partition返回一个数组数组时,我们使用.flatten. 我们不想丢失内部数组的层次结构,所以我们只请求一层扁平化:.flatten(1)
  • 整个东西被声明为Array类的一个方法,这样in就可以方便的使用了。由于该方法具有破坏性(它修改了原始数组),因此我们在其名称末尾添加了一个感叹号:.sink_nils!.
  • 最后,将该方法应用于现有阵列。
于 2013-06-26T14:42:09.853 回答
2

sort_by块必须返回一些总是可以比较的东西。添加unless阻止它这样做(因为块没有其他东西可以返回,并且nil不能与 a 进行比较Fixnum

a相反,当is时,您需要一个备用结果用作排序键nil

arr.sort_by{|a,b| a.nil? ? 999999999 : b[:length].to_i }
于 2013-06-26T13:24:20.420 回答