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.