Rozważmy prosty problem stosując zmienny mapę do śledzenia zdarzeń/liczby, tj:dostępu/zainicjować i aktualizacji wartości w zmienny mapie
val counts = collection.mutable.Map[SomeKeyType, Int]()
Mojego obecnego podejścia do zwiększany licznik jest:
counts(key) = counts.getOrElse(key, 0) + 1
// or equivalently
counts.update(key, counts.getOrElse(key, 0) + 1)
To wydaje mi się trochę niezgrabne, ponieważ muszę dwa razy określić klucz. Jeśli chodzi o wydajność, spodziewam się również, że key
musi znajdować się dwa razy na mapie, czego chciałbym uniknąć. Co ciekawe, ten problem z dostępem i aktualizacją nie wystąpiłby, gdyby Int
zapewniał pewien mechanizm do modyfikacji. Zmiana z Int
do klasy Counter
który zapewnia funkcję increment
byłoby na przykład umożliwiają:
// not possible with Int
counts.getOrElseUpdate(key, 0) += 1
// but with a modifiable counter
counts.getOrElseUpdate(key, new Counter).increment
Jakoś mam zawsze spodziewa się mieć następującą funkcjonalność z zmienny mapy (nieco podobny do transform
ale bez powrotu nową kolekcję i na konkretnym kluczu o wartości domyślnej):
// fictitious use
counts.updateOrElse(key, 0, _ + 1)
// or alternatively
counts.getOrElseUpdate(key, 0).modify(_ + 1)
Jednak o ile widzę, taka funkcjonalność nie istnieje. Czy nie miałoby sensu ogólnie (wydajność i składnia) mieć taką możliwość modyfikacji na miejscu? Prawdopodobnie po prostu czegoś tutaj brakuje ... Chyba musi być jakieś lepsze rozwiązanie tego problemu, aby taka funkcjonalność była niepotrzebna?
Aktualizacja:
powinienem wyjaśnić, że jestem świadomy withDefaultValue
ale problem pozostaje ten sam: wykonanie dwóch wyszukiwań jest nadal dwukrotnie jako powolny niż jeden, bez względu na to czy jest to O (1) działanie lub nie. Szczerze mówiąc, w wielu sytuacjach byłbym bardziej niż szczęśliwy z powodu przyspieszenia czynnika 2. I oczywiście konstrukcja zamknięcia modyfikacji może często zostać przeniesiona poza pętlę, więc nie jest to duży problem w porównaniu do uruchamiania operacja niepotrzebnie dwa razy.
Klucz odnośników w standardowym mapa powinna zwykle być O (1), więc nie jest to duży kara w poszukiwaniu go dwukrotnie - prawdopodobnie mniej niż jest wypłacana przez konstruowanie zamknięcie dla funkcji, aby przejść do 'updateOrElse'. – Impredicative
@Impredicative: To dobry punkt w tym przykładzie. Ale funkcjonalność samej cechy nie ma żadnego założenia. Na przykład 'Map' jest również implementowany przez' TreeMap' i 'ListMap', które są odpowiednio O (log N) i O (N). Zatem bez założenia O (1), modyfikacja na miejscu byłaby ogólnie pożądana. – bluenote10
jestem z wami, bluenote10 - Byłem pewien, że byłoby coś takiego 'map.update (klucz, initValue) {}' ponieważ wykonuje znacznie lepiej * i * jest czystsze. Jeśli wydajność nie ma znaczenia, prawdopodobnie nie używalibyśmy najpierw mapy Mutable Map. I jak wspomniano w innym komentarzu, '(_ + 1)' jest * nie * zamknięciem, ponieważ nie zamyka żadnych wolnych zmiennych - nie ma nic do skonstruowania. –
AmigoNico