Ruby - 如何使用sort_by将一个数组与另一个数组排序?

时间:2013-05-17 19:45:45

标签: ruby-on-rails ruby ruby-on-rails-3

我想对第一个数组进行排序:

 filenames = ["z.pdf", "z.txt", "a.pdf", "z.rf", "a.rf","a.txt", "z.html", "a.html"]

通过以下文件的扩展数组:

 extensions = ["html", "txt", "pdf", "rf"]

使用sort_by。但是当我尝试:

 filenames.sort_by { |x| extensions.index x.split('.')[1] }

我明白了:

 ["a.html", "z.html", "z.txt", "a.txt", "a.pdf", "z.pdf", "z.rf", "a.rf"]

扩展名为“txt”和“rf”的文件名未排序。我试图弄清sort_by如何使用元组进行排序,但无法找到sort_by的源代码。

如何使用sort_by按另一个数组对一个数组进行排序?


编辑:

结果如下:

["a.html", "z.html", "a.txt", "z.txt", "a.pdf", "z.pdf", "a.rf", "z.rf"]

7 个答案:

答案 0 :(得分:3)

sorted = filenames.sort_by do |filename|
  extension = File.extname(filename).gsub(/^\./, '')
  [
    extensions.index(extension) || -1,
    filename,
 ]
end
p sorted
# => ["a.html", "z.html", "a.txt", "z.txt", "a.pdf", "z.pdf", "a.rf", "z.rf"]

这使用了这样的事实:数组的排序顺序由它们的元素的排序顺序决定,按照它们的定义顺序。这意味着如果sort_by返回一个数组,则数组的第一个元素是主要排序顺序,第二个元素是辅助排序顺序,依此类推。我们利用它来按扩展名major,filename minor进行排序。

如果扩展名不在列表中,则此代码会根据||= -1将其放在首位。要将未知扩展名设置为最后,请将-1替换为extensions.size

答案 1 :(得分:3)

怎么样:

>> filenames.sort.group_by{ |s| File.extname(s)[1..-1] }.values_at(*extensions).flatten
[
    [0] "a.html",
    [1] "z.html",
    [2] "a.txt",
    [3] "z.txt",
    [4] "a.pdf",
    [5] "z.pdf",
    [6] "a.rf",
    [7] "z.rf"
]

group_by来自Enumerable,在我们的收藏工具箱中是一个不错的工具,让我们按“喜欢”属性对事物进行分组。在这种情况下,它会对文件的扩展名进行分组,使用File.extname检索,减去其前导“。”。

了解 File.extname为何非常重要。由于各种原因,文件可以包含由“。”分隔的多个部分。在这一点上简单地使用split('.')是灾难的一个方法,因为拆分后的代码必须处理两个以上的字符串。其他文件不包含分隔符'。'一点都不File.extname合理地尝试检索名称中找到的 last 扩展名,因此处理文件名和扩展名更为明智。来自文档:

File.extname("test.rb")         #=> ".rb"
File.extname("a/b/d/test.rb")   #=> ".rb"
File.extname("foo.")            #=> ""
File.extname("test")            #=> ""
File.extname(".profile")        #=> ""
File.extname(".profile.sh")     #=> ".sh"

values_at来自Hash,并按照传入的键/参数的顺序从哈希中提取值。这对于这种情况很有用,因为我们可以强制值的顺序与钥匙的顺序。如果你有一个巨大的哈希并想在一个动作中从中挑选某些值,values_at就是抓取的工具。如果您需要将“按扩展程序”排序设置不同,请更改extensions,输出将自动反映values_at的结果。

答案 2 :(得分:3)

按扩展数组的索引排序,然后按文件名:

排序
filenames = ["z.pdf", "z.txt", "a.pdf", "z.rf", "a.rf","a.txt", "z.html", "a.html"]
extensions = ["html", "txt", "pdf", "rf"]

p sorted = filenames.sort_by{|fn| [extensions.index(File.extname(fn)[1..-1]), fn]} #[1..-1] chops off the dot
#=> ["a.html", "z.html", "a.txt", "z.txt", "a.pdf", "z.pdf", "a.rf", "z.rf"]

答案 3 :(得分:1)

filenames.sort_by{|f| f.split(".").map{|base, ext|
  [extensions.index(ext), base]
}}

答案 4 :(得分:0)

filenames = ["z.pdf", "z.txt", "a.pdf", "z.rf", "a.rf","a.txt", "z.html", "a.html"]
extensions = ["html", "txt", "pdf", "rf"]
extensions.each_with_object([]){|k,ob| ob << filenames.find_all {|i| File.extname(i)[1..-1] == k }.sort}.flatten
#=> ["a.html", "z.html", "a.txt", "z.txt", "a.pdf", "z.pdf", "a.rf", "z.rf"]

答案 5 :(得分:0)

extensions = [".html", ".txt", ".pdf", ".rf"]
filenames.sort_by { |file_name_string|
  [ extensions.index( File.extname file_name_string ), file_name_string ]
}

答案 6 :(得分:-1)

无需使用File类。只是简单明了的正则表达式。

filenames.sort_by{|i| i.scan(/\..+$/)[0]}