【问题标题】:What is the best way to sort these types of strings?对这些类型的字符串进行排序的最佳方法是什么?
【发布时间】:2016-12-13 06:28:34
【问题描述】:

我需要获取目录和子目录中存在的所有文件,并且每个文件都有日期附加到文件名,如 product_log_2016-11-17.txt

为了获取我使用的目录中存在的文件列表

all_logs = Dir["#{Rails.root}/log/product_logs/**/*.txt"]

它会像这样返回完整路径文件(我已经从每个条目中删除了我的系统路径:

[
  "/log/product_logs/new_2/product_log_2016-11-17.txt",
  "/log/product_logs/new_2/products_log_2016-11-03.txt",
  "/log/product_logs/new_1/products_log_2016-10-04.txt",
  "/log/product_logs/new_1/product_log_2016-11-17.txt",
  "/log/product_logs/new_1/products_log_2016-11-03.txt"
]

但我想像这样按日期排序:

[
  "/log/product_logs/new_2/product_log_2016-11-17.txt",
  "/log/product_logs/new_1/product_log_2016-11-17.txt",
  "/log/product_logs/new_2/products_log_2016-11-03.txt",
  "/log/product_logs/new_1/products_log_2016-11-03.txt",
  "/log/product_logs/new_1/products_log_2016-10-04.txt"
]

我试过这样:

all_logs.sort{|a, b|b.split("/").last.split("_").last.split(".").first <=>a.split("/").last.split("_").last.split(".").first }

哪个有效,但似乎不是一个好的解决方案,谁能告诉我什么是排序这种类型列表的最佳方法?

【问题讨论】:

    标签: ruby-on-rails arrays ruby sorting


    【解决方案1】:
    ▶ input.sort_by { |i| [i[/\d{4}-\d{1,2}-\d{1,2}/], i[/\d+/]] }
    #⇒ [
    #    [0] "/log/product_logs/new_1/products_log_2016-10-04.txt",
    #    [1] "/log/product_logs/new_1/products_log_2016-11-03.txt",
    #    [2] "/log/product_logs/new_2/products_log_2016-11-03.txt",
    #    [3] "/log/product_logs/new_1/product_log_2016-11-17.txt",
    #    [4] "/log/product_logs/new_2/product_log_2016-11-17.txt"
    # ]
    

    与给出的答案相比有两个优势:

    • 它按new_??? 编号对同一日期进行排序,并且
    • sort_bysort 快​​得多。

    要接收降序排序,只需在最后链接到 Enumerable#reverse 的调用即可。

    【讨论】:

    • 一种更好的解决方案 +1 ,可能只需要 reverse
    • @dp7 是的,感谢有关reverse 的提示,已更新。
    • 日期为2016-8-03时会失败
    • @Thorin 如果月份和日期可能是 1 位数,请使用 \d{1,2} 匹配器,我已经更新了答案。
    【解决方案2】:

    你可以试试这个:

    all_logs = [
      "/log/product_logs/new_2/product_log_2016-11-17.txt",
      "/log/product_logs/new_2/products_log_2016-11-03.txt",
      "/log/product_logs/new_1/products_log_2016-10-04.txt",
      "/log/product_logs/new_1/product_log_2016-11-17.txt",
      "/log/product_logs/new_1/products_log_2016-11-03.txt"
    ]
    
    all_logs.sort { |a, b| b.split("/").last.to_date <=> a.split("/").last.to_date }
    

    【讨论】:

    • 有什么办法可以一次性得到文件列表,我的意思是得到列表后不需要排序?
    • @Thorin 我认为您必须在获取名称后明确进行排序。
    【解决方案3】:

    你可以这样做:

    # Returns:
    # 
    # [
    #    ["/log/product_logs/new_2/product_log_2016-11-17.txt", "2016-11-17"],
    #    ...
    # ]
    date_mapping = array.map { |s| [s, s.match(/\d{4}-\d{2}-\d{2}/)[0]] }
    
    # Sort arrays, and then get the first elements.
    date_mapping.sort { |a, b| [b[1], a[0]] <=> [a[1], b[0]] }.map(&:first)
    

    注意以下两行之间的区别:

    date_mapping.sort { |a, b| [b[1], a[0]] <=> [a[1], b[0]] }
    date_mapping.sort { |a, b| [b[1], b[0]] <=> [a[1], a[0]] }
    

    数组的第二个元素指定如何处理使用相同日期的字符串。

    【讨论】:

    • 似乎是一个更好的解决方案,但我只需要按日期排序,并且只需要获取那些与模式匹配的文件,我可以直接获取这些文件吗?比如 File.open(file_path, "rb").grep(/"id"=>123/)
    • Dir.glob:ruby-doc.org/core-1.9.3/Dir.html#method-c-glob你可以使用这样的模式(不是正则表达式):Dir.glob('*[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]*')
    猜你喜欢
    • 1970-01-01
    • 2012-03-05
    • 2014-01-03
    • 2017-04-04
    • 1970-01-01
    • 2020-06-01
    • 2020-02-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多