--- !ruby/object:RI::MethodDescription
aliases: []
block_params:
comment:
- !ruby/struct:SM::Flow::P
body: Sorts enum using a set of keys generated by mapping the values in enum through the given block.
- !ruby/struct:SM::Flow::VERB
body: " %w{ apple pear fig }.sort_by {|word| word.length}\n #=> ["fig", "pear", "apple"]\n"
- !ruby/struct:SM::Flow::P
body: The current implementation of sort_by generates an array of tuples containing the original collection element and the mapped value. This makes sort_by fairly expensive when the keysets are simple
- !ruby/struct:SM::Flow::VERB
body: " require 'benchmark'\n include Benchmark\n\n a = (1..100000).map {rand(100000)}\n\n bm(10) do |b|\n b.report("Sort") { a.sort }\n b.report("Sort by") { a.sort_by {|a| a} }\n end\n"
- !ruby/struct:SM::Flow::P
body: produces:
- !ruby/struct:SM::Flow::VERB
body: " user system total real\n Sort 0.180000 0.000000 0.180000 ( 0.175469)\n Sort by 1.980000 0.040000 2.020000 ( 2.013586)\n"
- !ruby/struct:SM::Flow::P
body: However, consider the case where comparing the keys is a non-trivial operation. The following code sorts some files on modification time using the basic sort method.
- !ruby/struct:SM::Flow::VERB
body: " files = Dir["*"]\n sorted = files.sort {|a,b| File.new(a).mtime <=> File.new(b).mtime}\n sorted #=> ["mon", "tues", "wed", "thurs"]\n"
- !ruby/struct:SM::Flow::P
body: "This sort is inefficient: it generates two new File objects during every comparison. A slightly better technique is to use the Kernel#test method to generate the modification times directly."
- !ruby/struct:SM::Flow::VERB
body: " files = Dir["*"]\n sorted = files.sort { |a,b|\n test(?M, a) <=> test(?M, b)\n }\n sorted #=> ["mon", "tues", "wed", "thurs"]\n"
- !ruby/struct:SM::Flow::P
body: This still generates many unnecessary Time objects. A more efficient technique is to cache the sort keys (modification times in this case) before the sort. Perl users often call this approach a Schwartzian Transform, after Randal Schwartz. We construct a temporary array, where each element is an array containing our sort key along with the filename. We sort this array, and then extract the filename from the result.
- !ruby/struct:SM::Flow::VERB
body: " sorted = Dir["*"].collect { |f|\n [test(?M, f), f]\n }.sort.collect { |f| f[1] }\n sorted #=> ["mon", "tues", "wed", "thurs"]\n"
- !ruby/struct:SM::Flow::P
body: This is exactly what sort_by does internally.
- !ruby/struct:SM::Flow::VERB
body: " sorted = Dir["*"].sort_by {|f| test(?M, f)}\n sorted #=> ["mon", "tues", "wed", "thurs"]\n"
full_name: Enumerable#sort_by
is_singleton: false
name: sort_by
params: |
enum.sort_by {| obj | block } => array
visibility: public