Iterando a través de un diccionario en Swift

221

Estoy un poco confundido con la respuesta que Xcode me está dando a este experimento en la Guía del lenguaje de programación Swift:

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

Yo entiendo que a medida que el diccionario está siendo atravesada, el número más grande se está creando a la variable, largest. Sin embargo, estoy confundido sobre por qué Xcode dice que largestse está configurando 5 veces, o 1 vez, o 3 veces, dependiendo de cada prueba.

Cuando reviso el código, veo que debe configurarse 6 veces solo en "Prime" (2, 3, 5, 7, 11, 13). Luego, debe omitir cualquier número en "Fibonacci", ya que todos son menores que el más grande, que actualmente está establecido en 13 desde "Prime". Luego, debe establecerse en 16, y finalmente en 25 en "Cuadrado", dando un total de 8 veces.

¿Me estoy perdiendo algo completamente obvio?

Nick Kohrn
fuente

Respuestas:

355

Los diccionarios en Swift (y otros idiomas) no están ordenados. Cuando itera por el diccionario, no hay garantía de que el orden coincida con el orden de inicialización. En este ejemplo, Swift procesa la tecla "Cuadrado" antes que las demás. Puede ver esto agregando una declaración de impresión al bucle. 25 es el quinto elemento de Square, por lo que el más grande se establecería 5 veces para los 5 elementos en Square y luego se mantendría en 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

Esto imprime:

kind: Square
kind: Prime
kind: Fibonacci
Guión
fuente
1
Muchas gracias! Estuve perplejo por un rato. Seguí agregando y eliminando números para cada tecla con la esperanza de diseccionarlo, pero no estaba llegando a ninguna parte. Su explicación es clara muy apreciada!
Nick Kohrn
15
let dict : [String : Any] = ["FirstName" : "Maninder" , "LastName" : "Singh" , "Address" : "Chandigarh"]
dict.forEach { print($0) }

El resultado sería

("Nombre", "Maninder") ("Apellido", "Singh") ("Dirección", "Chandigarh")

Maninderjit Singh
fuente
¿Podría decirme si este ejemplo es más eficiente en un bucle de 1000 datos? Porque tengo un JSON tan grande, así que me lleva un procesamiento de 1GB al final. Los dispositivos más nuevos no se bloquean, pero en mi iPhone 5s se bloquean 16 GB en la mitad de eso.
Daniel Arantes Loverde
Esto parece un poco engañoso dado que la pregunta original es sobre si los diccionarios mantienen su orden y luego publica un ejemplo en el que mantienen su orden cuando no lo hacen.
Declan McKenna
12

Esta es una función definida por el usuario para iterar a través de un diccionario:

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
fuente
11

Aquí hay una alternativa para ese experimento (Swift 3.0). Esto le dice exactamente qué tipo de número fue el más grande.

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
fuente
8

Si desea iterar sobre todos los valores:

dict.values.forEach { value in
    // print(value)
}
norbDEV
fuente
Odio tanto el hecho, que esto es correcto. ¡En la estúpida Joda, habla con el creador de Swift, todos deben hablar! 🤮
Sebastian
4

Las matrices son colecciones ordenadas, pero los diccionarios y los conjuntos son colecciones desordenadas. Por lo tanto, no puede predecir el orden de iteración en un diccionario o un conjunto.

Lea este artículo para saber más sobre los tipos de colección: lenguaje de programación rápido

Rachit Rawat
fuente
1

También puede usar values.makeIterator()para iterar sobre valores dict, como este:

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

También puede hacer la iteración de esta manera, en un estilo más rápido:

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

* sbItemses dict de tipo[String : NSManagedObject]

Yonathan Goriachnick
fuente