0Pricing
Swift Academy · Lezione

Uso dei KeyPath nelle collezioni

Ordini e trasformi le collezioni in base al key path.

Uso dei KeyPath nelle collezioni è una lezione Swift Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Swift Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Swift Academy include 4 lezioni in totale.

I key path brillano nelle collezioni

Le operazioni sulle collezioni come map, sorted e filter spesso leggono semplicemente una proprietà di ogni elemento. I key path consentono di esprimere questa intenzione senza scrivere una closure.

Swift accetta un key path ovunque sia prevista una funzione con un singolo argomento che restituisce un valore, perché un key path può essere usato come una funzione da Root a 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)

La sintassi abbreviata dei key path con map

Passare map(\.property) equivale a scrivere una closure che restituisce quella proprietà, ma è più breve e chiaro. La barra inversa e il punto iniziali consentono al compilatore di dedurre il tipo dell'elemento.

Confronti le due forme qui sotto: producono lo stesso risultato.

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> con un confronto tramite key path

Per ordinare in base a una proprietà, si scrive comunque una piccola closure di confronto, ma al suo interno si può leggere la proprietà tramite un key path per maggiore chiarezza.

Qui si ordinano le persone dalla più giovane alla più anziana confrontando i loro valori di 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))

Un helper riutilizzabile per l'ordinamento

Si può scrivere un helper generico che ordina qualsiasi array in base a una proprietà confrontabile, ricevendo la proprietà come argomento key path. In questo modo ordinare in base a un campo diventa una singola riga riutilizzabile in tutto il codice.

Il vincolo T: Comparable garantisce che la proprietà possa essere ordinata.

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))

Filtrare tramite un key path

Per filter serve un predicato che restituisca un Bool, quindi un key path di proprietà usato da solo funziona direttamente soltanto quando la proprietà è già un Bool.

Qui ogni attività ha un flag isDone e si filtra in base a questo flag usando la sintassi abbreviata dei key path.

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))

Filtrare in base a una proprietà non Bool

Quando si filtra in base a una proprietà non Bool, la si legge tramite un key path all'interno di una closure e la si confronta. Un helper generico può incapsulare questo schema per qualsiasi proprietà equatable.

Qui si conservano solo le persone la cui città corrisponde a una destinazione.

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> e <code>min</code> tramite key path

I metodi max(by:) e min(by:) ricevono una closure di confronto proprio come sorted. Si legge la proprietà tramite un key path per trovare l'elemento con il valore più grande o più piccolo.

Qui si trova la persona più anziana.

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)
}

Sommare una proprietà con reduce

Si possono combinare map(\.property) e reduce per sommare un campo numerico. Prima si proietta ogni elemento nel numero desiderato, poi si sommano tutti i valori.

Qui si sommano tutte le età in un'unica pipeline.

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)

Raggruppare tramite un key path

Dictionary(grouping:by:) raggruppa gli elementi in base al risultato di una closure. Si legge una proprietà tramite un key path per raggruppare in base a quel campo.

Qui le persone vengono raggruppate per città in un dizionario di array.

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) ?? [])

Ordinamento per più campi

Per ordinare in base a un campo e risolvere i pareggi con un altro, si confronta prima il key path principale e, quando i valori principali sono uguali, si passa a quello secondario.

Qui si ordina per età e poi per nome a parità di età.

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))

Perché qui i key path sono migliori delle closure

Usare i key path nelle chiamate alle collezioni riduce il codice ripetitivo, elimina il rischio di refusi nel corpo della closure e rende evidente l'intento: si sta proiettando un singolo campo.

Per trasformazioni complesse una closure resta lo strumento giusto, ma per una semplice lettura di proprietà \.property è la scelta più chiara.

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)

Verifica rapida: key path in map

Scelga la forma concisa con key path per estrarre una proprietà da ogni elemento.

Riepilogo: key path nelle collezioni

Ha visto come i key path rendano più conciso il codice che lavora con le collezioni:

  • map(\.property) proietta un singolo campo senza usare una closure.
  • filter(\.boolProperty) funziona direttamente per i campi Bool; per gli altri usi una closure con [keyPath:].
  • L'ordinamento, max e min leggono la proprietà tramite un key path all'interno delle rispettive closure di confronto.
  • Gli helper generici che ricevono un KeyPath trasformano l'ordinamento e il filtraggio in base a un campo in singole righe riutilizzabili.

Successivamente imparerà a usare i key path scrivibili, che consentono di impostare i valori oltre che di leggerli.

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))

Domande Frequenti

La lezione «Uso dei KeyPath nelle collezioni» è gratuita?

Sì — il testo completo di «Uso dei KeyPath nelle collezioni» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Swift Academy, passa a CoddyKit PRO. Il corso Swift Academy include 4 lezioni in totale.

Cosa imparerò in «Uso dei KeyPath nelle collezioni»?

Ordini e trasformi le collezioni in base al key path. Eserciti Swift Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Swift Academy?

Non è richiesta alcuna esperienza precedente. Swift Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «Uso dei KeyPath nelle collezioni»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Swift Academy?

Sì. Ogni lezione Swift Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Basi dei KeyPath
  2. Uso dei KeyPath nelle collezioni
  3. KeyPath scrivibili e di riferimento
  4. @dynamicMemberLookup
← Torna a Swift Academy