I have a dictionary declared like this:
var myDict = [Int : [Int]]()
The array in it is not initialized, so every time I have to check it first:
if (myDict[idx] == nil) {
myDict[idx] = []
}
How to initialize it as an empty array in MyDict declaration?
I think you could be misunderstanding something pretty key - let's make sure:
The way the dictionary works, is not to have one array, but an array for each key.
Each value of 'idx' you request the array for returns a different array.
You can't expect it to return an empty array - a dictionary is meant to return a nil value for a key that hasn't been set. To do what you're trying, the following would probably do the trick:
myDict[idx] = myDict[idx] ?? []
That's what dictionary do if you try to retrieve a key for which no value exists.
You can subclass Dictionary and override the subscript func to get what you want like this. Or simply write an extension, or write a operator defination to use a different symbol.
“You can also use subscript syntax to retrieve a value from the dictionary for a particular key. Because it is possible to request a key for which no value exists, a dictionary’s subscript returns an optional value of the dictionary’s value type. ”
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 2.1).” iBooks. https://itunes.apple.com/cn/book/swift-programming-language/id881256329?l=en&mt=11
You can initialize it this way
myDict.forEach {
(var dictElement) -> () in
dictElement.1 = [Int]()
}
Related
I got the string value from server like this.
let filename = "\(eventList[index]["filename"])"
But I got the value with Optional(Optional(stringValue)).
So I changed that like this.
let filename = "\(eventList[index]["filename"]!)"
Then I got the value with Optional(stringValue).
I can't do any more for this error.
How can I read the filename without any optional?
Use nil-coalescing operator aka double question mark operation. It is used to provide a default value when unwrapping an optional type.
let filename = eventList[index]["filename"] ?? ""
R̶e̶f̶:̶ ̶h̶t̶t̶p̶:̶/̶/̶w̶w̶w̶.̶j̶e̶e̶n̶a̶l̶i̶n̶f̶o̶t̶e̶c̶h̶.̶c̶o̶m̶/̶b̶l̶o̶g̶s̶/̶i̶o̶s̶/̶h̶o̶w̶-̶t̶o̶-̶d̶o̶-̶o̶p̶t̶i̶o̶n̶a̶l̶-̶v̶a̶r̶i̶a̶b̶l̶e̶-̶a̶s̶s̶i̶g̶n̶m̶e̶n̶t̶-̶w̶i̶t̶h̶-̶d̶e̶f̶a̶u̶l̶t̶-̶v̶a̶l̶u̶e̶-̶d̶o̶u̶b̶l̶e̶-̶q̶u̶e̶s̶t̶i̶o̶n̶-̶m̶a̶r̶k̶/̶
https://medium.com/#milanpanchal24/
Use if-let syntax to unwrap optional:
if let fileName = eventList[index]["filename"] {
// use fileName
}
eventList[index] accesses an array item at the given index. The item you are referring seems to be an optional dictionary so before accessing the dictionary item it needs to be unwrapped: eventLists[index]! (assuming it exists and valid of course otherwise it will crash)
then you can access the dictionary require value which is an optional as well:
eventLists[index]!["fileName"]!
assuming your list is valid you will get the desired String object.
I recommend using the safety checks (if-let or other variants) for preventing crashes
I have a custom class with different computed properties. One of them is a Dictionary of [String: String]. The getter is no problem, but I don't know how to use the setter: How can I figure out, what was the last value added to the dictionary? Obviously newValue.last doesn't exists (.first does!).
EDIT:
This seems to work:
var myProp: [String: String] {
get { ... }
set {
let lastVal = newValue[newValue.startIndex.advancedBy(newValue.count-1)]
...
}
BUT: will this always return the last added value?
EDIT 2
The first edit is wrong. A dictionary is unordered and with this way it's not sure, if it really returns the last added key and value. See my answer below.
As you point out, a Dictionary is an unorderd collection of key-value pairs, so there is no last getter (first is just a convenience for what in Objective-C was more appropriately called anyObject) . The Dictionary also does not keep track of the order items were added.
To get the last item, there are two possibilities. You could refactor to use an array, e.g. of tuples (key, value); or you could keep track of the last item added in a separate variable.
But maybe there is a misunderstanding about the "setter". A setter sets the entire object.
set { myProp = newValue }
So if you have a myProp = ["foo": "bar"], the entire dictionary in myProp is overwritten with this data.
What you want is to add a key to the property. In Swift, this is done by subscripting.
myProp["foo"] = "bar"
You do not have to implement anything special in the get closure.
Note that you have to remember two things, though: first, the dictionary has to be properly initialized; second, any existing item will be overwritten if the new value uses the identical key.
I understand now... the dictionary is unordered. To really get the last added value, I have to compare the value itself with the newValue. The working code:
var myProp: [String: String] {
get { // doing things to read the things and add them to a dictionary }
set {
var new = newValue
for (key, value) in myProp {
if new[key] == value {
new.removeValueForKey(key)
}
}
// now 'new' should only have one key and one value, that one, that just was added
}
}
I am now writing a program involves class and dictionaries. I wonder how could I access a class's values inside a dictionary. For the code below how do I access the test1 value using the dictionary. I have tried using dict[1].test1but it doesn't work.
class test {
var tes1 = 1
}
var refer = test()
var dict = [1:refer]
There are a few problems with the line dict[1].test1:
Firstly, the subscript on a dictionary returns an optional type because there may not be a value for the key. Therefore you need to check a value exists for that key.
Secondly, in your class Test you've defined a variable tes1, but you're asking for test1 from your Dictionary. This was possibly just a type-o though.
To solve these problems you're code should look something like this:
if let referFromDictionary = dict[1] {
prinln(referFromDictionary.test1)
}
That's because the subscript returns an optional, so you have to unwrap it - and the most straightforward way is by using optional chaining:
dict[1]?.tes1
but you can also use optional binding:
if let test = dict[1] {
let value = test.tes1
}
I want to check if there is a value in a array and if so assign to a String using a if-left statement:
if let scoreValue = scoreValueArray[element!]{
// do something with scoreValue
}
Error: Bound value in a conditional binding must be of optional type
So tried changing the ! to ? but error persists.
Any input appreciated.
scoreValueArray is an array of strings, where a String value is appended to array if a condition is met, then array is saved to NSUserdefaults.
So element is a int which corresponds to a index in the array, bt only if the index is occupied with a String, so
scoreValueArray[element!]
could return an 'Index out of bounds', hence want to use the if-let.
Although the accepted answer clearly puts why optional binding is not available in the current implementation, it doesn't provide with a solution.
As it is shown in this answer, protocols provide an elegant way of safely checking the bounds of an array. Here's the Swift 2.0 version:
extension Array {
subscript (safe index: Int) -> Element? {
return indices ~= index ? self[index] : nil
}
}
Which you can use like this:
let fruits = ["Apple", "Banana", "Cherry"]
if let fruit = fruits[safe: 4] {
// Do something with the fruit
}
It's not clear what type your scoreValueArray is, but for the sake of this answer, I'm going to assume it's an array of Int.
var scoreValueArray: Array<Int>
Now, if we look the definition of the Array struct, we'll find this:
struct Array<T> : MutableCollectionType, Sliceable {
// other stuff...
subscript (index: Int) -> T
// more stuff
}
So, calling the subscript method on our array (which is what we do when we say scoreValueArray) returns a non-optional. And non-optionals cannot be used in the conditional binding if let/if var statements.
We can duplicate this error message in a more simple example:
let foo: Int = 3
if let bar = foo {
// same error
}
This produces the same error. If we instead do something more like the following, we can avoid the error:
let foo: Int? = 3
if let bar = foo {
// perfectly valid
}
This is different from a dictionary, whose subscript method does return an optional (T?). A dictionary will return a value if the key passed in the subscript is found or nil if there is no value for the passed key.
We must avoid array-index-out-of-bounds exceptions in the same way we always do... by checking the array's length:
if element < scoreValueArray.count {
scoreValue = scoreValueArray[element]
}
I'm trying to implement a basic multimap in Swift. Here's a relevant (non-functioning) snippet:
class Multimap<K: Hashable, V> {
var _dict = Dictionary<K, V[]>()
func put(key: K, value: V) {
if let existingValues = self._dict[key] {
existingValues += value
} else {
self._dict[key] = [value]
}
}
}
However, I'm getting an error on the existingValues += value line:
Could not find an overload for '+=' that accepts the supplied arguments
This seems to imply that the value type T[] is defined as an immutable array, but I can't find any way to explicitly declare it as mutable. Is this possible in Swift?
The problem is that you are defining existingValues as a constant with let. However, I would suggest changing the method to be:
func put(key: K, value: V) {
var values = [value]
if let existingValues = self._dict[key] {
values.extend(existingValues)
}
self._dict[key] = values
}
}
I feel that the intent of this is clearer as it doesn't require modifying the local array and reassigning later.
if var existingValues = self._dict[key] { //var, not let
existingValues += value;
// should set again.
self._dict[key] = existingValues
} else {
self._dict[key] = [value]
}
Assignment and Copy Behavior for Arrays
The assignment and copy behavior for Swift’s Array type is more complex than for its Dictionary type. Array provides C-like performance when you work with an array’s contents and copies an array’s contents only when copying is necessary.
If you assign an Array instance to a constant or variable, or pass an Array instance as an argument to a function or method call, the contents of the array are not copied at the point that the assignment or call takes place. Instead, both arrays share the same sequence of element values. When you modify an element value through one array, the result is observable through the other.
For arrays, copying only takes place when you perform an action that has the potential to modify the length of the array. This includes appending, inserting, or removing items, or using a ranged subscript to replace a range of items in the array. If and when array copying does take place, the copy behavior for an array’s contents is the same as for a dictionary’s keys and values, as described in Assignment and Copy Behavior for Dictionaries.
See: https://itunes.apple.com/us/book/the-swift-programming-language/id881256329?mt=11
Buckets is a data structures library for swift. It provides a multimap and allows subscript notation.
One easy way to implement a multi-map is to use a list of pairs (key, value) sorted by key, using binary search to find ranges of entries. This works best when you need to get a bunch of data, all at once. It doesn't work so well when you are constantly deleting and inserting elements.
See std::lower_bound from C++ for a binary search implementation which can be easily written in swift.