2012-05-31 23 views
9

Jak mogę znormalizować listę argumentów funkcji do łańcucha, tak, że dwie listy argumentów są konwertowane na ten sam ciąg, ponieważ są one faktycznie równoważne? Algorytm powinienJak znormalizować argumenty funkcji Perla do zapamiętania?

  1. Porównaj osadzonych mieszań i list głęboko, raczej niż przez odniesienie
  2. Ignoruj ​​hash kolejność kluczy
  3. Ignoruj ​​różnicę między 3 a „3”
  4. generować stosunkowo czytelny ciąg (nie jest wymagany, ale ładne-to-mieć do debugowania)
  5. Wykonaj dobrze (xs preferowanego przez Perl)

jest to konieczne dla memoization, tj. Buforowanie wyniku funkcji na podstawie jej argumentów.

Jako Strawman przykład Memoize wykorzystuje to jako domyślny normalizer, która nie # 1 i # 3:

$argstr = join chr(28),@_; 

na chwilę moim iść do normalizer był

JSON::XS->new->utf8->canonical 

jednak traktuje liczbę 3 i ciąg "3" differently, w oparciu o ostatnio używany skalar. Może to generować różne ciągi dla zasadniczo równoważnych list argumentów i zmniejszać korzyści z zapisu. (. Zdecydowana większość funkcji nie będzie wiedział, czy obchodzi czy oni dostać 3 lub „3”)

dla zabawy Spojrzałem na pęczek serializers aby przekonać się, które różnicują 3 i „3”:

Data::Dump : equal - [3] vs [3] 
Data::Dumper : not equal - [3] vs ['3'] 
FreezeThaw : equal - FrT;@1|@1|$1|3 vs FrT;@1|@1|$1|3 
JSON::PP  : not equal - [3] vs ["3"] 
JSON::XS  : not equal - [3] vs ["3"] 
Storable  : not equal - <unprintable> 
YAML   : equal - ---\n- 3\n vs ---\n- 3\n 
YAML::Syck : equal - --- \n- 3\n vs --- \n- 3\n 
YAML::XS  : not equal - ---\n- 3\n vs ---\n- '3'\n 

Z tych, które zgłaszają "równy", nie wiesz, jak zmusić ich do zignorowania kolejności haszowania.

Mógłbym przejrzeć listę argumentów z wyprzedzeniem i powiązać wszystkie numery, ale wymagałoby to wykonania głębokiej kopii i naruszenia 5.

Dzięki!

+0

Istnieje również [Test :: Więcej] (http://metacpan.org/module/Test::Więcej), a jest_deeply, i [Test :: Deep] (http://metacpan.org/module/Test :: Deep) - eq_deeply. – Ether

Odpowiedz

2

Prawie każdy serializer będzie traktował 3 i "3" inaczej, ponieważ nie ma wiedzy, że liczba i usztywniona liczba są takie same dla ciebie i to założenie jest fałszywe dla danych ogólnych. Musisz samodzielnie znormalizować wejście lub wyjście.

Dla danych wejściowych, dogłębne skanowanie z zastąpieniem dowolnego szarpanego numeru jego wartością + 0 spowoduje wykonanie. Jeśli wiesz, gdzie dokładnie mogą znajdować się cyfry, możesz znacznie skrócić ten skan.

W przypadku wyjścia, niektóre proste maszyny stanów lub nawet wyrażenie regularne (tak, wiem, że dane wyjściowe nie są regularne) będą najprawdopodobniej wystarczające do usunięcia wartości liczbowych tylko łańcuchów liczbowych.

+0

Cóż, nie, mam listę wielu serializerów powyżej (takich jak Data :: Dump i FreezeThaw), które nie. :) Być może masz na myśli "każdy dobry serializator * powinien * traktować 3 i" 3 "inaczej". Nie jestem tego taki pewien, biorąc pod uwagę łatwość i arbitralność, z jaką wartości Perla mogą przechodzić między ciągiem a liczbą. –

+0

Ponownie skanując, wspomniałem, że skanowanie wejścia jest niepożądane ze względu na wydajność. Jeśli to musi być zrobione, chciałbym, żeby był w XS. Ale byłoby znacznie wydajniej, gdyby serializator miał opcję, by po prostu wyłączyć to wyróżnienie. –

+0

Co powiecie o skanowaniu wyjściowym? Powinno to być wystarczająco szybkie. Jednym z ważnych plusów w porównaniu z zależnymi od nieudokumentowanych dziwactw jest to, że zawsze możesz mieć pewność, że ręcznie usunięte wartości zostaną faktycznie usunięte. –

2

YAML i jego domyślne klawisze skrótów sortowania potomnego. Ustaw $YAML::SortKeys = 2, aby sortować na głębokich haszach.

Ustawienie $YAML::Stringify na wartość true i ustawienie wartości $YAML::XS::QuoteNumericStrings na wartość false pomoże w znormalizowaniu wartości liczbowych. To ostatnie ustawienie spowoduje "zanotowanie" wartości ciągu, która wygląda jak liczba.


Ponadto, można użyć $Data::Dumper::Sortkeys = 1 normalizować rozkaz wyjścia z Data::Dumper. Ustawienie $Data::Dumper::Useqq = 1 spowoduje anulowanie ciągów, które wyglądają jak cyfry.

+0

Niestety, ale nie, YAML :: XS będzie zachowywał się tak, jak powinien to zrobić każdy serializator. Wypróbuj 'perl -MYAML :: XS -e 'my $ v =" 0333 "; drukuj YAML :: XS :: Dump $ v; $ v + 0; drukuj YAML :: XS :: Dump $ v; print "$ v \ n"; '' –

+0

@Oleg V. Volkov - dzięki waszemu komentarzowi dowiedziałem się więcej o tym, do czego służy' $ YAML :: XS :: QuoteNumericStrings' i edytowałem moją odpowiedź. Ale myślę, że "0333" 'i' "333" 'i' 0333' (tj. 219) powinny być traktowane jako różne dane wejściowe przez OP. – mob

+0

Tylko "333" będzie działać dokładnie tak samo. –

Powiązane problemy