Iterowanie po słowniku w Swift

222

Jestem trochę zdezorientowany odpowiedzią Xcode na ten eksperyment w Swift Programming Language Guide:

// Use a for-in to iterate through a dictionary (experiment)

let interestingNumbers = [
    "Prime": [2, 3, 5, 7, 11, 13],
    "Fibonacci": [1, 1, 2, 3, 5, 8],
    "Square": [1, 4, 9, 16, 25]
]
var largest = 0
for (kind, numbers) in interestingNumbers {
    for number in numbers {
        if number > largest {
            largest = number
        }
    }
}
largest

Rozumiem, że jako słownika jest transversed, największa liczba ta jest zestaw do zmiennej largest. Jestem jednak zdezorientowany, dlaczego Xcode mówi, że largestjest ustawiany 5 razy lub 1 raz lub 3 razy, w zależności od każdego testu.

Przeglądając kod, widzę, że należy go ustawić 6 razy w samym „Prime” (2, 3, 5, 7, 11, 13). Następnie powinien pomijać dowolne liczby w „Fibonacci”, ponieważ wszystkie są mniejsze od największej, która obecnie jest ustawiona na 13 od „Prime”. Następnie powinien być ustawiony na 16, a na końcu 25 na „Square”, dając w sumie 8 razy.

Czy brakuje mi czegoś całkowicie oczywistego?

Nick Kohrn
źródło

Odpowiedzi:

355

Słowniki w Swift (i innych językach) nie są uporządkowane. Podczas iteracji w słowniku nie ma gwarancji, że kolejność będzie zgodna z kolejnością inicjowania. W tym przykładzie Swift przetwarza klucz „Kwadrat” przed innymi. Możesz to zobaczyć, dodając do pętli instrukcję print. 25 jest piątym elementem kwadratu, więc największy byłby ustawiony 5 razy dla 5 elementów na kwadracie, a następnie pozostałby na 25.

let interestingNumbers = [
    "Prime": [2, 3, 5, 7, 11, 13],
    "Fibonacci": [1, 1, 2, 3, 5, 8],
    "Square": [1, 4, 9, 16, 25]
]
var largest = 0
for (kind, numbers) in interestingNumbers {
    println("kind: \(kind)")
    for number in numbers {
        if number > largest {
            largest = number
        }
    }
}
largest

To drukuje:

kind: Square
kind: Prime
kind: Fibonacci
Dziarskość
źródło
1
Dziękuję bardzo! Przez chwilę byłem zakłopotany. Ciągle dodawałem i usuwałem liczby dla każdego klucza w nadziei, że go przeanalizuję, ale nigdzie nie dotarłem. Twoje wyjaśnienie jest jasne, bardzo mile widziane!
Nick Kohrn
15
let dict : [String : Any] = ["FirstName" : "Maninder" , "LastName" : "Singh" , "Address" : "Chandigarh"]
dict.forEach { print($0) }

Wynik byłby

(„FirstName”, „Maninder”) („LastName”, „Singh”) („Address”, „Chandigarh”)

Maninderjit Singh
źródło
Czy możesz mi powiedzieć, czy ten przykład jest bardziej wydajny w pętli danych 1000? Ponieważ mam JSON tak duży, więc na koniec zajmuje mi 1 GB. Nowsze urządzenia nie ulegają awarii, ale w moim iPhonie 5s 16 GB ulega awarii na połowie tego.
Daniel Arantes Loverde,
Wydaje się to nieco mylące, biorąc pod uwagę, że pierwotne pytanie dotyczy tego, czy słowniki zachowują swoją kolejność, a następnie podajesz przykład, w którym zachowują swoją kolejność, gdy nie.
Declan McKenna,
12

Jest to funkcja zdefiniowana przez użytkownika do iteracji w słowniku:

func findDic(dict: [String: String]){
    for (key, value) in dict{
    print("\(key) : \(value)")
  }
}

findDic(dict: ["Animal":"Lion", "Bird":"Sparrow"])
//prints Animal : Lion 
         Bird : Sparrow
Rawand Saeed
źródło
11

Oto alternatywa dla tego eksperymentu (Swift 3.0). To mówi dokładnie, jaki rodzaj liczby był największy.

let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]

var largest = 0
var whichKind: String? = nil

for (kind, numbers) in interestingNumbers {
    for number in numbers {
    if number > largest {
        whichKind = kind
        largest = number
    }
  }
}

print(whichKind)
print(largest)

OUTPUT:
Optional("Square")
25
jabbyApps
źródło
8

Jeśli chcesz iterować wszystkie wartości:

dict.values.forEach { value in
    // print(value)
}
norbDEV
źródło
Nienawidzę tego faktu tak bardzo, że to prawda. W głupiej Jodzie mów do twórcy szybkiego, wszyscy muszą mówić! 🤮
Sebastian
4

Tablice są kolekcjami uporządkowanymi, ale słowniki i zestawy są kolekcjami nieuporządkowanymi. Dlatego nie można przewidzieć kolejności iteracji w słowniku lub zestawie.

Przeczytaj ten artykuł, aby dowiedzieć się więcej o typach kolekcji: Swift Programming Language

Rachit Rawat
źródło
1

Możesz także użyć values.makeIterator()do iteracji po wartościach dykt, takich jak:

for sb in sbItems.values.makeIterator(){
    // do something with your sb item..
    print(sb)
}

Możesz także wykonać taką iterację w bardziej płynnym stylu:

sbItems.values.makeIterator().forEach{
    // $0 is your dict value..
    print($0) 
}

* sbItemsjest dykta typu[String : NSManagedObject]

Yonathan Goriachnick
źródło