ruby-on-rails - ruby 重新排序日期数组,字符串部分保留空字符串

标签 ruby-on-rails arrays ruby sorting date

我有这个包含空字符串的日期数组,我想以两种方式对其重新排序,每种情况下空字符串都应始终位于数组的前面。

[" ", "2018-10-01", "2019", " ",  "2019-06-20", "2019-06", "2019-10", "2019-01-01", "2017", "2018-05", "2018", "2018-05-10",  " "]

第一个结果就是这样重新排序

["", "", "", "2019-10-01", "2019-10", "2019-06-20", "2019-06", "2019", "2018-01-01", "2018-05", "2018-05-10", "2017"]

我希望能够以这种方式重新排序的第二种方式:

[" ", " ", " ", "2017", "2018-01-01", "2019-06-20", "2019-06", "2019-10-01", "2019-10", "2019"]

我尝试了下面的代码,但没有得到想要的结果。

  ["", "", "", "2019-10-01", "2019-10", "2019-06-20", "2019-06", "2019", "2018-01-01", "2018-05", "2018-05-10", "2017"].sort_by { |date| parts = date.split('-').map(&:to_i) }

更新

升序排序能不能按这个顺序出来。 yy-mm-dd,然后是 yy-mm,然后是年份,这意味着升序排序应该采用这种形式 ["", "", "", "2017","2018-05-10", "2018-05", "2018-10-01", "2018", "2019-01-01", "2019-06-20", "2019-06", "2019-10", "2019"].所以它不是常规的升序排序,而是基于导致上述顺序的模式。

相同的模式适用于降序排序。

最佳答案

解决方案 #1 - 正常排序

您可以首先根据字符串是否为空这一事实对列表进行分区。然后对所有当前日期进行排序并将它们连接在一起。

dates = [" ", "2018-10-01", "2019", " ",  "2019-06-20", "2019-06", "2019-10", "2019-01-01", "2017", "2018-05", "2018", "2018-05-10",  " "]

asc = ->(a, b) { a <=> b }
desc = ->(a, b) { b <=> a }

blank, present = dates.partition(&:blank?)
result1 = blank + present.sort(&desc)
#=> [" ", " ", " ", "2019-10", "2019-06-20", "2019-06", "2019-01-01", "2019", "2018-10-01", "2018-05-10", "2018-05", "2018", "2017"]
result2 = blank + present.sort(&asc)
#=> [" ", " ", " ", "2017", "2018", "2018-05", "2018-05-10", "2018-10-01", "2019", "2019-01-01", "2019-06", "2019-06-20", "2019-10"]

注意:这只是根据字母顺序对数组进行排序。只要您使用的是 yyyy-mm-dd 格式(如果只有一位数字,则处理为零)就可以了。如果日期以另一种格式提供,您希望先将它们转换为日期。

解决方案 #2 - 假设缺失月份或日期的最大值

strings = [" ", "2018-10-01", "2019", " ",  "2019-06-20", "2019-06", "2019-10", "2019-01-01", "2017", "2018-05", "2018", "2018-05-10",  " "]

array_to_date = lambda do |(year, month, day)|
  month ||= 12
  day ||= 31

  begin
    Date.new(year, month, day)
  rescue ArgumentError
    raise unless (1..12).cover? month
    raise unless (1..31).cover? day
    array_to_date.call([year, month, day - 1])
  end
end

date_regex = /\A(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?\z/
yyyy_mm_dd = ->(date_string) { date_regex.match(date_string).captures.compact.map(&:to_i) }
string_to_date = yyyy_mm_dd >> array_to_date

asc = ->(a, b) { string_to_date.call(a) <=> string_to_date.call(b) }
desc = ->(a, b) { string_to_date.call(b) <=> string_to_date.call(a) }

dates, non_dates = strings.partition(&date_regex.method(:match?))
result1 = non_dates + dates.sort(&desc)
#=> [" ", " ", " ", "2019", "2019-10", "2019-06", "2019-06-20", "2019-01-01", "2018", "2018-10-01", "2018-05", "2018-05-10", "2017"]
result2 = non_dates + dates.sort(&asc)
#=> [" ", " ", " ", "2017", "2018-05-10", "2018-05", "2018-10-01", "2018", "2019-01-01", "2019-06-20", "2019-06", "2019-10", "2019"]

注意:这不是最有效的解决方案,因为每次调用 #sort block 时都必须转换字符串。如果您正在使用大型数组,您可以先转换所有值并将它们保存在散列中。然后在排序时查找它们。

当前的正则表达式还允许像 "0000-00-00" 这样的字符串通过,您可能想让它更具体一些。

关于ruby-on-rails - ruby 重新排序日期数组,字符串部分保留空字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56605945/

相关文章:

ruby-on-rails - 与 ransack 排序不同

ruby /Rspec : should be_false vs should == false

javascript - 了解 React 服务器端渲染中使用 .dispatch 和箭头函数链接的 .map 和 .filter

ruby-on-rails - 复杂类别下拉取决于存在的叶节点

ruby - OpenStruct 和 Hash 之间有哪些重要区别?

ruby-on-rails - 如何从模型内部检查 ActiveRecord 中是否存在关联?

ruby-on-rails - ActiveRecord的查找器方法之间的区别:取vs限制(1)

ruby-on-rails - 销毁前验证

c# - 数组访问的安全元素

arrays - Bash - 将文件中的通配符模式读入数组