Jaki jest najbardziej skuteczny sposób sprawdzenia, czy dwa hashe h1
i h2
mają ten sam zestaw kluczy, nie biorąc pod uwagę zamówienia? Czy można to uczynić szybszym lub bardziej zwięzłym z większą skutecznością niż odpowiedź, którą publikuję?Sprawdź, czy dwa skróty mają ten sam zestaw kluczy.
Odpowiedz
Spróbuj:
# Check that both hash have the same number of entries first before anything
if h1.size == h2.size
# breaks from iteration and returns 'false' as soon as there is a mismatched key
# otherwise returns true
h1.keys.all?{ |key| !!h2[key] }
end
gorszy scenariusz, byłbyś iteracji tylko poprzez klawisze raz.
Jeszcze lepiej, 'h2.include? (Key)'. – akuhn
Zrobiłem kilka benchmarków i wydaje się, że ta odpowiedź jest jak dotąd jasnym zwycięzcą. Użycie 'Hash # include?' Nie przynosi żadnej poprawy wydajności, ale z pewnością jest dobrym krokiem naprzód pod względem czytelności. – Jan
'if a then b end' ->' a && b' – tokland
To moja próba:
(h1.keys - h2.keys).empty? and (h2.keys - h1.keys).empty?
Łączenie freemasonjson's i sawa's pomysłów:
h1.size == h2.size and (h1.keys - h2.keys).empty?
Jest to również interesujące. – sawa
To zależy od Twoich danych.
Nie ma tak naprawdę ogólnego przypadku . Na przykład generalne pobieranie całego zestawu kluczy naraz jest szybsze niż sprawdzanie osobnego włączenia każdego klucza. Jeśli jednak w zestawie danych zestawy kluczy różnią się często, wówczas wolniejsze rozwiązanie, które nie działa szybciej, może być szybsze. Na przykład:
h1.size == h2.size and h1.keys.all?{|k|h2.include?(k)}
Kolejnym czynnikiem, który należy wziąć pod uwagę, jest wielkość haszy. Jeśli są duże rozwiązanie z wyższym kosztem instalacji, jak dzwoni Set.new
może się opłacać, jeśli jednak są one małe, że nie będzie:
h1.size == h2.size and Set.new(h1.keys) == Set.new(h2.keys)
A jeśli zdarzy się porównać te same niezmienne mieszań w kółko ponownie, zdecydowanie zapłaci za buforowanie wyników.
Ostatecznie tylko benchmark powie, ale, aby napisać benchmark, musielibyśmy wiedzieć więcej o twoim przypadku użycia. Na pewno testowanie rozwiązania za pomocą danych syntetycznych (jak na przykład klucze generowane losowo) nie będzie reprezentatywne.
dla samego posiadania przynajmniej odniesienia na to pytanie ...
require 'securerandom'
require 'benchmark'
a = {}
b = {}
# Use uuid to get a unique random key
(0..1_000).each do |i|
key = SecureRandom.uuid
a[key] = i
b[key] = i
end
Benchmark.bmbm do |x|
x.report("#-") do
1_000.times do
(a.keys - b.keys).empty? and (a.keys - b.keys).empty?
end
end
x.report("#&") do
1_000.times do
computed = a.keys & b.keys
computed.size == a.size
end
end
x.report("#all?") do
1_000.times do
a.keys.all?{ |key| !!b[key] }
end
end
x.report("#sort") do
1_000.times do
a_sorted = a.keys.sort
b_sorted = b.keys.sort
a == b
end
end
end
Wyniki są następujące:
Rehearsal -----------------------------------------
#- 1.000000 0.000000 1.000000 ( 1.001348)
#& 0.560000 0.000000 0.560000 ( 0.563523)
#all? 0.240000 0.000000 0.240000 ( 0.239058)
#sort 0.850000 0.010000 0.860000 ( 0.854839)
-------------------------------- total: 2.660000sec
user system total real
#- 0.980000 0.000000 0.980000 ( 0.976698)
#& 0.560000 0.000000 0.560000 ( 0.559592)
#all? 0.250000 0.000000 0.250000 ( 0.251128)
#sort 0.860000 0.000000 0.860000 ( 0.862857)
muszę zgodzić się z @akuhn że byłoby to lepsze wzorzec porównawczy, gdybyśmy mieli więcej informacji na temat używanego zestawu danych. Ale biorąc to pod uwagę, uważam, że to pytanie naprawdę wymagało ciężkiego faktu.
Zalecam dodanie nazwy testu porównawczego do metody 'raport' jako parametru. Umożliwi to dodanie nazwy do raportu o wynikach, co znacznie ułatwia czytanie. –
Dobrze, łammy wszystkie zasady savoir vivre i przenośność. Interfejs API MRI wchodzi w grę.
/* Name this file superhash.c. An appropriate Makefile is attached below. */
#include <ruby/ruby.h>
static int key_is_in_other(VALUE key, VALUE val, VALUE data) {
struct st_table *other = ((struct st_table**) data)[0];
if (st_lookup(other, key, 0)) {
return ST_CONTINUE;
} else {
int *failed = ((int**) data)[1];
*failed = 1;
return ST_STOP;
}
}
static VALUE hash_size(VALUE hash) {
if (!RHASH(hash)->ntbl)
return INT2FIX(0);
return INT2FIX(RHASH(hash)->ntbl->num_entries);
}
static VALUE same_keys(VALUE self, VALUE other) {
if (CLASS_OF(other) != rb_cHash)
rb_raise(rb_eArgError, "argument needs to be a hash");
if (hash_size(self) != hash_size(other))
return Qfalse;
if (!RHASH(other)->ntbl && !RHASH(other)->ntbl)
return Qtrue;
int failed = 0;
void *data[2] = { RHASH(other)->ntbl, &failed };
rb_hash_foreach(self, key_is_in_other, (VALUE) data);
return failed ? Qfalse : Qtrue;
}
void Init_superhash(void) {
rb_define_method(rb_cHash, "same_keys?", same_keys, 1);
}
Oto plik Makefile.
CFLAGS=-std=c99 -O2 -Wall -fPIC $(shell pkg-config ruby-1.9 --cflags)
LDFLAGS=-Wl,-O1,--as-needed $(shell pkg-config ruby-1.9 --libs)
superhash.so: superhash.o
$(LINK.c) -shared $^ -o [email protected]
Sztuczny, syntetyczny i uproszczony benchmark pokazuje, co następuje.
require 'superhash'
require 'benchmark'
n = 100_000
h1 = h2 = {a:5, b:8, c:1, d:9}
Benchmark.bm do |b|
# freemasonjson's state of the art.
b.report { n.times { h1.size == h2.size and h1.keys.all? { |key| !!h2[key] }}}
# This solution
b.report { n.times { h1.same_keys? h2} }
end
# user system total real
# 0.310000 0.000000 0.310000 ( 0.312249)
# 0.050000 0.000000 0.050000 ( 0.051807)
Dobra robota, sir! – akuhn
woah thats awesome! Muszę wracać do poznania C – bitstrider
Dzięki za szczegóły. – sawa
- 1. Sprawdź, czy dwa ciągi mają taki sam wzorzec powtarzanych znaków.
- 2. Czy dwa elementy div mają ten sam pasek przewijania?
- 3. Dlaczego dwa urządzenia mają ten sam główny numer urządzenia?
- 4. Dlaczego typy ogólne mają ten sam podpis?
- 5. Jak sprawdzić, czy dwa selektory jQuery wybrały ten sam element
- 6. OpenGL, tekstury mają zawsze ten sam rozmiar
- 7. Sprawdź, czy 2 tablice zawierają ten sam element (Swift 2.0)
- 8. Sprawdź, czy klucze hash obejmują cały zestaw kluczy
- 9. Jak uzyskać FxCop mają ten sam zestaw reguł, co w przypadku analizy kodu programu Visual Studio?
- 10. T-SQL - Zdobądź listę wszystkich As, które mają ten sam zestaw Bs
- 11. Jak określić, które rdzenie logiczne mają ten sam rdzeń fizyczny?
- 12. Dlaczego obiekty utworzone w pętli mają ten sam adres?
- 13. Czy działa ten sam program addEventListener?
- 14. Komponenty mają ten sam identyfikator w środku: powtórzenie
- 15. Dlaczego różne wersje zespołów Silverlight mają ten sam numer wersji?
- 16. Eclipse RCP: mają ten sam edytor otwarty w oknie edytora
- 17. Metody obiektu tej samej klasy mają ten sam identyfikator?
- 18. mercurial: sprawdź, czy gałąź zawiera zestaw zmian
- 19. Emacs: ten sam bufor, dwa okna, jeden zwężony, jeden nie
- 20. Jak odczytać ten sam plik dwa razy z rzędu
- 21. dodając ten sam obiekt dwa razy do ManyToManyField
- 22. Dwa różne nasiona produkujące ten sam „” losową sekwencję
- 23. Magento $ zamówienia-> getAllItems() zwracają dwa razy ten sam element
- 24. Ten sam adres dwóch zmiennych?
- 25. Określanie, czy słownik zawiera cały zestaw kluczy
- 26. Co by się stało, gdyby dwa komunikaty Git miały ten sam skrót SHA-1?
- 27. Dlaczego nawiasy mają wpływ na skróty?
- 28. Numpy: najszybszy sposób sprawdzenia, czy wszystkie elementy tablicy mają ten sam znak?
- 29. Czy Ruby 1.8 i 1.9 mają ten sam kod skrótu dla ciągu znaków?
- 30. Sprawdź istnienie HashMap kluczy
Czy porównać to z 'h1.keys.sort == h2.keys.sort'? –
Zrobiłem z ograniczonym przykładem. 'h1.keys.sort == h2.keys.sort' było nieco wolniejsze. Ale nie jestem pewien, czy tak jest w ogóle. – sawa
Myślę, że powinieneś o tym wspomnieć w pytaniu. A także zamieściłbym rozwiązanie jako część pytania, a nie jako odpowiedź. –