0Pricing
Swift Academy · Lekcja

Używanie KeyPath w kolekcjach

Sortowanie i mapowanie kolekcji według ścieżki klucza.

Używanie KeyPath w kolekcjach to bezpłatna lekcja Swift Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Swift Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Swift Academy zawiera 4 lekcji w sumie.

Ścieżki kluczy w kolekcjach

Operacje na kolekcjach, takie jak map, sorted i filter, często tylko odczytują jedną właściwość każdego elementu. Ścieżki kluczy pozwalają wyrazić ten zamiar bez pisania domknięcia.

Swift akceptuje ścieżkę klucza wszędzie tam, gdzie oczekiwana jest funkcja przyjmująca jeden argument i zwracająca wartość, ponieważ ścieżki kluczy można użyć jako funkcji przekształcającej Root w Value.

struct Person {
    let name: String
    let age: Int
}

let people = [Person(name: "Ana", age: 30), Person(name: "Ben", age: 25)]
let names = people.map(\.name)
print(names)

Skrótowa postać mapowania ze ścieżką klucza

Przekazanie map(\.property) jest równoważne zapisaniu domknięcia, które zwraca tę właściwość, ale jest krótsze i czytelniejsze. Początkowe ukośnik odwrotny i kropka pozwalają kompilatorowi wywnioskować typ elementu.

Porównaj poniższe dwie postacie — dają ten sam wynik.

struct Person {
    let name: String
    let age: Int
}

let people = [Person(name: "Ana", age: 30), Person(name: "Ben", age: 25)]
let closureForm = people.map { $0.age }
let keyPathForm = people.map(\.age)
print(closureForm)
print(keyPathForm)

<code>sorted(by:)</code> z porównaniem opartym na ścieżce klucza

Aby sortować według właściwości, nadal trzeba napisać krótkie domknięcie porównujące, ale można w nim odczytać właściwość za pomocą ścieżki klucza, co poprawia czytelność.

Tutaj sortujemy osoby od najmłodszej do najstarszej, porównując ich wartości age.

struct Person {
    let name: String
    let age: Int
}

let people = [Person(name: "Ana", age: 30), Person(name: "Ben", age: 25)]
let path = \Person.age
let sorted = people.sorted { $0[keyPath: path] < $1[keyPath: path] }
print(sorted.map(\.name))

Pomocnicza funkcja sortująca wielokrotnego użytku

Można napisać funkcję pomocniczą generyczną, która posortuje dowolną tablicę według dowolnej właściwości obsługującej porównywanie, przyjmując tę właściwość jako argument będący ścieżką klucza. Dzięki temu sortowanie według właściwości sprowadza się w całym projekcie do jednej linii kodu.

Ograniczenie T: Comparable zapewnia, że właściwość może być uporządkowana.

func sorted<E, T: Comparable>(_ array: [E], by path: KeyPath<E, T>) -> [E] {
    array.sorted { $0[keyPath: path] < $1[keyPath: path] }
}

struct Person { let name: String; let age: Int }
let people = [Person(name: "Ana", age: 30), Person(name: "Ben", age: 25)]
print(sorted(people, by: \.age).map(\.name))

Filtrowanie za pomocą ścieżki klucza

W przypadku filter potrzebne jest predykat zwracający wartość Bool, dlatego sama ścieżka klucza właściwości działa bezpośrednio tylko wtedy, gdy właściwość jest już typu Bool.

Tutaj każde zadanie ma flagę isDone, a filtrowanie odbywa się na jej podstawie za pomocą skrótowej postaci ścieżki klucza.

struct Task {
    let title: String
    let isDone: Bool
}

let tasks = [Task(title: "A", isDone: true), Task(title: "B", isDone: false)]
let finished = tasks.filter(\.isDone)
print(finished.map(\.title))

Filtrowanie według właściwości innej niż Bool

Podczas filtrowania według właściwości innej niż Bool należy odczytać ją za pomocą ścieżki klucza wewnątrz domknięcia i porównać. Generyczna funkcja pomocnicza może ująć ten schemat dla dowolnej właściwości obsługującej porównywanie równościowe.

Tutaj pozostawiamy tylko osoby, których miasto jest zgodne z wartością docelową.

struct Person { let name: String; let city: String }

func filter<E, T: Equatable>(_ array: [E], _ path: KeyPath<E, T>, equals value: T) -> [E] {
    array.filter { $0[keyPath: path] == value }
}

let people = [Person(name: "Ana", city: "Oslo"), Person(name: "Ben", city: "Rome")]
print(filter(people, \.city, equals: "Oslo").map(\.name))

<code>max</code> i <code>min</code> według ścieżki klucza

Metody max(by:) i min(by:) przyjmują domknięcie porównujące, podobnie jak sorted. Odczytaj właściwość za pomocą ścieżki klucza, aby znaleźć element o największej lub najmniejszej wartości.

Tutaj znajdujemy najstarszą osobę.

struct Person { let name: String; let age: Int }

let people = [Person(name: "Ana", age: 30), Person(name: "Ben", age: 25), Person(name: "Cy", age: 41)]
let path = \Person.age
if let oldest = people.max(by: { $0[keyPath: path] < $1[keyPath: path] }) {
    print(oldest.name)
}

Sumowanie właściwości za pomocą <code>reduce</code>

Można połączyć map(\.property) z reduce, aby zsumować pole liczbowe. Najpierw należy przekształcić każdy element w potrzebną liczbę, a następnie dodać wszystkie liczby.

Tutaj sumujemy wszystkie wartości wieku w jednym potoku.

struct Person { let name: String; let age: Int }

let people = [Person(name: "Ana", age: 30), Person(name: "Ben", age: 25)]
let totalAge = people.map(\.age).reduce(0, +)
print(totalAge)

Grupowanie według ścieżki klucza

Dictionary(grouping:by:) umieszcza elementy w grupach na podstawie wyniku domknięcia. Odczytaj właściwość za pomocą ścieżki klucza, aby grupować według tej właściwości.

Tutaj osoby są grupowane według miasta w słowniku tablic.

struct Person { let name: String; let city: String }

let people = [
    Person(name: "Ana", city: "Oslo"),
    Person(name: "Ben", city: "Rome"),
    Person(name: "Cy", city: "Oslo")
]
let path = \Person.city
let byCity = Dictionary(grouping: people, by: { $0[keyPath: path] })
print(byCity["Oslo"]?.map(\.name) ?? [])

Sortowanie według wielu właściwości

Aby sortować według jednej właściwości, a remisy rozstrzygać za pomocą innej, należy najpierw porównać podstawową ścieżkę klucza, a gdy wartości podstawowe są równe, użyć pomocniczej.

Tutaj sortujemy według wieku, a następnie według imienia osób w tym samym wieku.

struct Person { let name: String; let age: Int }

let people = [
    Person(name: "Zoe", age: 30),
    Person(name: "Ana", age: 30),
    Person(name: "Ben", age: 25)
]
let sorted = people.sorted {
    if $0[keyPath: \Person.age] != $1[keyPath: \Person.age] {
        return $0.age < $1.age
    }
    return $0.name < $1.name
}
print(sorted.map(\.name))

Dlaczego w tym przypadku ścieżki kluczy są lepsze od domknięć

Używanie ścieżek kluczy w wywołaniach operacji na kolekcjach ogranicza powtarzalny kod, eliminuje ryzyko literówki w treści domknięcia i jasno pokazuje zamiar: projekcję pojedynczego pola.

W przypadku złożonych przekształceń domknięcie nadal jest właściwym narzędziem, ale przy zwykłym odczycie właściwości \.property jest najczytelniejszym wyborem.

struct Product { let name: String; let price: Double }

let products = [Product(name: "Pen", price: 2), Product(name: "Pad", price: 5)]
let names = products.map(\.name)
let prices = products.map(\.price)
print(names)
print(prices)

Szybkie sprawdzenie: ścieżka klucza w <code>map</code>

Wybierz zwięzłą postać ścieżki klucza do wyodrębniania jednej właściwości z każdego elementu.

Podsumowanie: ścieżki kluczy w kolekcjach

Ścieżki kluczy pozwalają pisać zwięzły kod operujący na kolekcjach:

  • map(\.property) odwzorowuje pojedyncze pole bez domknięcia.
  • filter(\.boolProperty) działa bezpośrednio dla pól typu Bool; dla pozostałych należy użyć domknięcia z [keyPath:].
  • Sortowanie oraz max i min odczytują właściwość za pomocą ścieżki klucza wewnątrz domknięć porównujących.
  • Generyczne funkcje pomocnicze przyjmujące KeyPath zamieniają sortowanie i filtrowanie według pola w wielokrotnie używane rozwiązania zapisane w jednej linii.

W następnej części poznasz zapisywalne ścieżki kluczy, które pozwalają nie tylko odczytywać wartości, lecz także je ustawiać.

struct Person { let name: String; let age: Int }

let people = [Person(name: "Ana", age: 30), Person(name: "Ben", age: 25)]
let youngestFirst = people.sorted { $0[keyPath: \Person.age] < $1[keyPath: \Person.age] }
print(youngestFirst.map(\.name))

Często zadawane pytania

Czy lekcja „Używanie KeyPath w kolekcjach” jest bezpłatna?

Tak — pełny tekst „Używanie KeyPath w kolekcjach” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Swift Academy, przejdź na CoddyKit PRO. Kurs Swift Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Używanie KeyPath w kolekcjach”?

Sortowanie i mapowanie kolekcji według ścieżki klucza. Ćwiczysz Swift Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Swift Academy?

Nie wymagamy żadnego doświadczenia. Swift Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Używanie KeyPath w kolekcjach”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Swift Academy?

Tak. Każda lekcja Swift Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Podstawy KeyPath
  2. Używanie KeyPath w kolekcjach
  3. Zapisywalne i referencyjne KeyPath
  4. @dynamicMemberLookup
← Powrót do Swift Academy