I'd like to sort the first array:
filenames = ["z.pdf", "z.txt", "a.pdf", "z.rf", "a.rf","a.txt", "z.html", "a.html"]
by the following file's extensions array:
extensions = ["html", "txt", "pdf", "rf"]
using sort_by. But when I try:
filenames.sort_by { |x| extensions.index x.split('.')[1] }
I get:
["a.html", "z.html", "z.txt", "a.txt", "a.pdf", "z.pdf", "z.rf", "a.rf"]
The filenames with extensions "txt" and "rf" are not sorted. I've tried to figure out how sort_by sorts by using a tuple but haven't been able to find the source code for sort_by.
How can I sort one array by another array using sort_by?
Edit:
The result should look like:
["a.html", "z.html", "a.txt", "z.txt", "a.pdf", "z.pdf", "a.rf", "z.rf"]
Sort by the index of the extensions array, then the filename:
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"]
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"]
This uses the fact that the sort order of arrays is determined by the sort order of their elements, in the order they are defined. That means that if sort_by returns an array, the first element of the array is the primary sort order, the second element is the secondary sort order, and so on. We exploit that to sort by extension major, filename minor.
If an extension is not in the list, this code puts it first by virtue of ||= -1. To put an unknown extension last, replace -1 with extensions.size.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With