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?

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

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


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

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

8

Jeśli chcesz iterować wszystkie wartości:

dict.values.forEach { value in
    // print(value)
}

Nienawidzę tego faktu tak bardzo, że to prawda. W głupiej Jodzie mów do twórcy szybkiego, wszyscy muszą mówić! 🤮
Sebastian


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]

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.