Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift expression error (ambiguous without more context)

Tags:

swift

I'm new to Swift, currently practising some basic stuffs, when I try to figure out why dictionary content is not ordered, I found an answer from someone's post, the solution is add an index before it, like this:

[Int [String, String]]

when I tried to test it, there's an error about

expression type '[Dictionary<Int, Dictionary<String, Int>>]' is ambiguous without more context

no idea what went wrong, so I'll just show the code and look for help.

var animalNumbers = [[1: ["Cat": 1]], [2: ["Dog": 10]], [3: ["Aye-Aye": 98]]]

for (key, (animal, num)) in animalNumbers {
    print ("\(animal) = \(num)")
}
like image 249
zhuqh93 Avatar asked Aug 14 '17 06:08

zhuqh93


1 Answers

I suspect you may have misunderstood that suggestion about the numeric key.

First, let's step back. I assume your original dictionary was as follows, and you were trying to solve the issue that the order wasn't preserved:

let animals = ["Cat": 1, "Dog": 10, "Aye-Aye": 98]

And I suspect you read that other answer and concluded that you needed to convert that to:

let animalNumbers = [[1: ["Cat": 1]], [2: ["Dog": 10]], [3: ["Aye-Aye": 98]]]

That's an array of nested dictionaries, with each dictionary having a numeric key. But that doesn't make sense. You're solving the problem twice. It's an ordered array of dictionaries, and the numeric key then also provides a mechanism for retrieving the values in some particular order. That's redundant.

The numeric key idea is to make that a dictionary whose key is a numeric value, and whose values are, themselves, dictionaries. If you were to do that, it's simpler than what you have there, but instead merely:

let animalNumbers = [0: ["Cat": 1], 1: ["Dog": 10], 2: ["Aye-Aye": 98]]

Note, that's a dictionary with numeric key, [Int: [String: Int]]. Anyway, once you have that dictionary, you can then theoretically do:

for i in 0 ..< animalNumbers.count {
    for (name, value) in animalNumbers[i]! {
        print(name, value)
    }
}

But, having reverse engineered what I suspect that other answer was suggesting, I should say that it's really not a very good pattern. If you want to insert values, you have to go through a nightmare of rebuilding all of those numeric keys.

Instead, just use a simple array of dictionaries, [[String: Int]], which is ordered, but eliminates many problems introduced with that manually constructed numeric key:

let animals = [["Cat": 1], ["Dog": 10], ["Aye-Aye": 98]]

Then you can:

for dictionary in animals {
    for (name, value) in dictionary {
        print(name, value)
    }
}

Finally, even better, you shouldn't be dealing with arrays of dictionaries, but rather an array of custom types:

struct Animal {
    let name: String
    let value: Int
}

let animals = [
    Animal(name: "Cat", value: 1),
    Animal(name: "Dog", value: 10),
    Animal(name: "Aye-Aye", value: 98)
]

Now that you're dealing with [Animal] type, you can just:

for animal in animals {
    print(animal.name, animal.value)
}
like image 114
Rob Avatar answered Dec 19 '22 11:12

Rob