Chciałbym przypisać funkcję do wszystkich klawiszy w słowniku. Miałem nadzieję, że coś takiego zadziała, ale nie można zastosować filtra bezpośrednio do słownika. Jaki jest najczystszy sposób osiągnięcia tego?
W tym przykładzie próbuję zwiększyć każdą wartość o 1. Jednak jest to przypadkowe w tym przykładzie - głównym celem jest ustalenie, jak zastosować map () do słownika.
var d = ["foo" : 1, "bar" : 2]
d.map() {
$0.1 += 1
}
swift
dictionary
Maria Zverina
źródło
źródło
map
robi a . to, o co prosisz, to sposób na ukrycie iteracji za rozszerzeniem / zamknięciem, dzięki czemu nie musisz na to patrzeć za każdym razem, gdy go używasz.Odpowiedzi:
Swift 4+
Dobre wieści! Swift 4 zawiera
mapValues(_:)
metodę, która tworzy kopię słownika z tymi samymi kluczami, ale różnymi wartościami. Zawiera również plikfilter(_:)
przeciążenia, która zwracaDictionary
iinit(uniqueKeysWithValues:)
iinit(_:uniquingKeysWith:)
inicjatorów, aby utworzyćDictionary
z dowolnej sekwencji krotki. Oznacza to, że jeśli chcesz zmienić zarówno klucze, jak i wartości, możesz powiedzieć coś takiego:Istnieją również nowe interfejsy API do łączenia ze sobą słowników, zastępowania wartości domyślnej brakujących elementów, grupowania wartości (konwertowanie kolekcji do słownika tablic z kluczem wynikającym z odwzorowania kolekcji na jakiejś funkcji) i nie tylko.
Podczas dyskusji nad propozycją SE-0165 , która wprowadziła te funkcje, kilkakrotnie przywołałem tę odpowiedź Stack Overflow i myślę, że sama liczba głosów za pomogła zademonstrować zapotrzebowanie. Więc dziękuję za pomoc w ulepszaniu Swift!
źródło
map
który może generować sprzeczne klucze, jest nadal przydatnymap
w wielu sytuacjach. (Z drugiej strony można argumentować, że mapowanie tylko wartości jest naturalną interpretacjąmap
słowników - zarówno przykład oryginalnego postera, jak i mój, modyfikują tylko wartości, a koncepcyjniemap
tablica modyfikuje tylko wartości, a nie indeksy.)try
:return Dictionary<Key, OutValue>(try map { (k, v) in (k, try transform(v)) })
DictionaryExtension.swift:13:16: Argument labels '(_:)' do not match any available overloads
Argument labels '(_:)' do not match any available overloads
, wdrażając to ostatnie rozszerzenie. Nie bardzo wiem, jak to rozwiązać: /Dictionary
inicjatora dodanego w jednym z poprzednich przykładów. Upewnij się, że uwzględnisz oba z nich.Dzięki Swift 5 możesz użyć jednego z pięciu poniższych fragmentów , aby rozwiązać problem.
# 1. Korzystanie z
Dictionary
mapValues(_:)
metody# 2. Korzystanie z
Dictionary
map
metody iinit(uniqueKeysWithValues:)
inicjatora# 3. Używając
Dictionary
reduce(_:_:)
metody lubreduce(into:_:)
metody# 4. Korzystanie z
Dictionary
subscript(_:default:)
indeksu dolnego# 5. Korzystanie z
Dictionary
subscript(_:)
indeksu dolnegoźródło
Podczas gdy większość odpowiedzi tutaj koncentruje się na mapowaniu całego słownika (kluczy i wartości), pytanie tak naprawdę dotyczyło tylko mapowania wartości. Jest to ważne rozróżnienie, ponieważ mapowanie wartości pozwala zagwarantować taką samą liczbę wpisów, podczas gdy mapowanie zarówno klucza, jak i wartości może skutkować zduplikowanymi kluczami.
Oto rozszerzenie,
mapValues
które umożliwia mapowanie tylko wartości. Zauważ, że rozszerza również słownik oinit
z sekwencji par klucz / wartość, co jest nieco bardziej ogólne niż inicjowanie go z tablicy:źródło
func mapValues<T>(_ transform: (_ value: Value) -> T) -> [Key: T] { var result = [Key: T]() for (key, val) in self { result[key] = transform(val) } return result }
. Uważam, że to też lepiej się czyta. Czy występuje problem z wydajnością?Najprościej jest po prostu dodać
map
do Słownika:Sprawdzanie, czy działa:
Wynik:
źródło
SequenceType.map
nie jest to funkcja mutująca. Twój przykład mógłby zostać przepisany tak, aby był zgodny z istniejącą umowąmap
, ale to jest to samo, co zaakceptowana odpowiedź.Możesz także użyć
reduce
zamiast mapy.reduce
jest w stanie zrobić wszystko, comap
może, a nawet więcej!Byłoby dość łatwo opakować to w rozszerzenie, ale nawet bez rozszerzenia pozwala robić to, co chcesz, za pomocą jednego wywołania funkcji.
źródło
let newDict = oldDict.reduce([String:Int]()) { (var dict, pair) in dict["new\(pair.1)"] = pair.1; return dict }
Okazuje się, że możesz to zrobić. To, co musisz zrobić, to utworzyć tablicę na podstawie
MapCollectionView<Dictionary<KeyType, ValueType>, KeyType>
zwróconych przezkeys
metodę słowników . ( Informacje tutaj ) Możesz następnie zmapować tę tablicę i przekazać zaktualizowane wartości z powrotem do słownika.źródło
Zgodnie z podręcznikiem Swift Standard Library Reference, mapowanie jest funkcją tablic. Nie dla słowników.
Ale możesz iterować swój słownik, aby zmodyfikować klucze:
źródło
Szukałem sposobu, aby zmapować słownik bezpośrednio do wpisanej tablicy z niestandardowymi obiektami. Znalazłem rozwiązanie w tym rozszerzeniu:
Używając go w następujący sposób:
źródło
Szybki 3
Próbuję na łatwy sposób w Swift 3.
Chcę zamapować [String: String?] Na [String: String] , używam forEach zamiast map lub flat map.
źródło
Szybki 5
Funkcja mapy słownika ma taką składnię.
dictData.map(transform: ((key: String, value: String)) throws -> T)
możesz po prostu ustawić wartości zamknięcia na to
Wynik będzie:
Może to być ostrzeżenie
Result of call to 'map' is unused
Następnie wystarczy ustawić
_ =
przed zmienną.Może to ci pomoże Dziękuję.
źródło
Zakładam, że problemem jest zachowanie kluczy naszego oryginalnego słownika i mapowanie w jakiś sposób wszystkich jego wartości.
Uogólnijmy i powiedzmy, że możemy chcieć odwzorować wszystkie wartości na inny typ .
Więc to, od czego chcielibyśmy zacząć, to słownik i zamknięcie (funkcja), a na końcu nowy słownik. Problem polega oczywiście na tym, że ścisłe pisanie Swifta przeszkadza. Zamknięcie musi określać, jaki typ wchodzi i jaki wychodzi, dlatego nie możemy utworzyć metody, która przyjmuje ogólne zamknięcie - z wyjątkiem kontekstu ogólnego. Dlatego potrzebujemy funkcji ogólnej.
Inne rozwiązania koncentrują się na robieniu tego w ogólnym świecie samej struktury ogólnej Dictionary, ale łatwiej mi jest myśleć w kategoriach funkcji najwyższego poziomu. Na przykład moglibyśmy napisać to, gdzie K jest typem klucza, V1 jest typem wartości słownika początkowego, a V2 jest typem wartości słownika końcowego:
Oto prosty przykład nazywania go, aby udowodnić, że rodzaj ogólny rzeczywiście rozwiązuje się sam w czasie kompilacji:
Zaczęliśmy od słownika,
[String:Int]
a skończyliśmy na słowniku[String:String]
, przekształcając wartości pierwszego słownika poprzez zamknięcie.(EDYCJA: Teraz widzę, że jest to w rzeczywistości to samo, co rozwiązanie AirspeedVelocity, z wyjątkiem tego, że nie dodałem dodatkowej elegancji inicjalizatora słownika, który tworzy Dictionary z sekwencji zip.)
źródło
Szybki 3
Stosowanie:
Rozbudowa:
źródło
Próbujesz tylko zmapować wartości (potencjalnie zmieniając ich typ), dołącz to rozszerzenie:
Biorąc pod uwagę, że masz ten słownik:
Transformacja wartości jednowierszowej wygląda wtedy następująco:
Przekształcenie wartości wieloliniowej wygląda wówczas następująco:
źródło
Innym podejściem jest do
map
słownika ireduce
, gdzie funkcjekeyTransform
ivalueTransform
są funkcjami.źródło
Swift 3 , użyłem tego,
Stosowanie:
Nr ref
źródło