Каков самый быстрый способ сортировки хэша?
Люди часто спрашивают, что является лучшим способом сортировки хэша, но затем они не задают требуемого последующего вопроса о том, что является самым быстрым способом, который действительно определяет лучший способ.
Каков самый быстрый способ сортировки Hash в Ruby, независимо от используемой версии Ruby?
Я ищу дополнительные ответы, которые будут охватывать угловые случаи, или раскрыть проблемы с более универсальными и/или самыми быстрыми методами.
Ответы
Ответ 1
Каков самый быстрый способ сортировки хэша?
require 'fruity'
HASH = Hash[('a'..'z').to_a.shuffle.map{ |k| [k, 1] }]
def sort_hash1(h)
h.sort.to_h
end
def sort_hash2(h)
Hash[h.sort]
end
def sort_hash3(h)
Hash[h.sort_by{ |k, v| k }]
end
def sort_keys(h)
keys = h.keys.sort
Hash[keys.zip(h.values_at(*keys))]
end
puts "Running on Ruby v#{ RUBY_VERSION }"
puts
compare do
do_sort_hash1 { sort_hash1(HASH) } if [].respond_to?(:to_h)
do_sort_hash2 { sort_hash2(HASH) }
do_sort_hash3 { sort_hash3(HASH) }
do_sort_keys { sort_keys(HASH) }
end
Выполнение вышеуказанного кода на ноутбуке Mac OS приводит к следующему выводу:
# >> Running on Ruby v2.2.2
# >>
# >> Running each test 256 times. Test will take about 1 second.
# >> do_sort_keys is faster than do_sort_hash3 by 39.99999999999999% ± 10.0%
# >> do_sort_hash3 is faster than do_sort_hash1 by 1.9x ± 0.1
# >> do_sort_hash1 is similar to do_sort_hash2
и
# >> Running on Ruby v1.9.3
# >>
# >> Running each test 256 times. Test will take about 1 second.
# >> do_sort_keys is faster than do_sort_hash3 by 19.999999999999996% ± 10.0%
# >> do_sort_hash3 is faster than do_sort_hash2 by 4x ± 0.1
Удвоение размера хэша:
HASH = Hash[[*('a'..'z'), *('A'..'Z')].shuffle.map{ |k| [k, 1] }]
Результаты в:
# >> Running on Ruby v2.2.2
# >>
# >> Running each test 128 times. Test will take about 1 second.
# >> do_sort_keys is faster than do_sort_hash3 by 50.0% ± 10.0%
# >> do_sort_hash3 is faster than do_sort_hash1 by 2.2x ± 0.1
# >> do_sort_hash1 is similar to do_sort_hash2
и
# >> Running on Ruby v1.9.3
# >>
# >> Running each test 128 times. Test will take about 1 second.
# >> do_sort_keys is faster than do_sort_hash3 by 30.000000000000004% ± 10.0%
# >> do_sort_hash3 is faster than do_sort_hash2 by 4x ± 0.1
Значения будут меняться в зависимости от аппаратного обеспечения, но относительные результаты не должны изменяться.
Fruity был выбран с использованием встроенного Benchmark для простоты.
Это было вызвано "Сортировка хеша по ключу, возвратить хэш в Ruby.
Ответ 2
Вот еще несколько интересных вещей, которые следует учитывать:
require 'fruity'
puts "Running Ruby v#{ RUBY_VERSION }"
# >> Running Ruby v2.2.2
require 'fruity'
puts "Running Ruby v#{ RUBY_VERSION }"
# >> Running Ruby v2.2.2
Здесь рассматриваются различия с использованием целого числа в качестве ключа:
HASH = Hash[[*(1..100)].shuffle.map{ |k| [k, 1] }]
compare do
_sort1 { HASH.sort.to_h }
_sort2 { HASH.sort{ |a, b| a[0] <=> b[0] }.to_h }
_sort3 { HASH.sort{ |a, b| a.first <=> b.first }.to_h }
_sort_by { HASH.sort_by{ |k,v| k }.to_h }
end
# >> Running each test 64 times. Test will take about 1 second.
# >> _sort_by is faster than _sort2 by 70.0% ± 1.0%
# >> _sort2 is faster than _sort3 by 19.999999999999996% ± 1.0%
# >> _sort3 is faster than _sort1 by 19.999999999999996% ± 1.0%
Здесь рассматриваются различия с использованием односимвольной строки в качестве ключа:
HASH = Hash[[*('a'..'Z')].shuffle.map{ |k| [k, 1] }]
compare do
_sort1 { HASH.sort.to_h }
_sort2 { HASH.sort{ |a, b| a[0] <=> b[0] }.to_h }
_sort3 { HASH.sort{ |a, b| a.first <=> b.first }.to_h }
_sort_by { HASH.sort_by{ |k,v| k }.to_h }
end
# >> Running each test 16384 times. Test will take about 1 second.
# >> _sort1 is similar to _sort3
# >> _sort3 is similar to _sort2
# >> _sort2 is faster than _sort_by by 1.9x ± 0.1
Ответ 3
Это сравнение sort
и sort_by
при доступе к более сложному объекту:
require 'fruity'
RUBY_VERSION # => "2.2.2"
class Foo
attr_reader :key
def initialize(k)
@key = k
end
def <=>(b)
self.key <=> b.key
end
end
HASH = Hash[[*(1..100)].shuffle.map{ |k| [Foo.new(k), 1] }]
compare do
_sort1 { HASH.sort.to_h }
_sort_by { HASH.sort_by{ |k,v| k.key }.to_h }
end
# >> Running each test 32 times. Test will take about 1 second.
# >> _sort_by is faster than _sort1 by 2.7x ± 0.1