我有这个包含空字符串的日期数组,我想以两种方式对其重新排序,每种情况下空字符串都应始终位于数组的前面。
[" ", "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/