Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby - How do I sort one array with another array using sort_by?

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"]
like image 940
James Testa Avatar asked Apr 15 '26 03:04

James Testa


2 Answers

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"]
like image 135
steenslag Avatar answered Apr 17 '26 16:04

steenslag


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.

like image 25
Wayne Conrad Avatar answered Apr 17 '26 16:04

Wayne Conrad



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!