Immutable Dictionary value change - swift

Can we change any pair value in let type Dictionary in Swift Langauage.
like :
let arr2 : AnyObject[] = [1, "23", "hello"]
arr2[1] = 23
arr2 // output: [1,23,"hello"]
let arr1 :Dictionary<Int,AnyObject> = [1: "One" , 2 : 2]
arr1[2] = 4 // not posible error
arr1
In Case of Immutable Array we can change its value like above but not in case of Immutable
Dictionary. Why?

This is taken from The Swift Programming Language book:
For dictionaries, immutability also means that you cannot replace the
value for an existing key in the dictionary. An immutable dictionary’s
contents cannot be changed once they are set.
Immutability has a slightly different meaning for arrays, however. You
are still not allowed to perform any action that has the potential to
change the size of an immutable array, but you are allowed to set a
new value for an existing index in the array.

Array declared with let has only immutable length. Contents can still be changed.
Dictionary declared with let is completely immutable, you can't change contents of it. If you want, you must use var instead of let.

Swift has changed a lot since then.
Array and Dictionary are value types. When declared with let, they cannot change any more. Especially, one cannot re-assign them, or the elements in them.
But if the type of the elements is reference type, you can change the properties of the elements in Array or Dictionary.
Here is a sample.(run in Xcode6 beta-6)
class Point {
var x = 0
var y = 0
}
let valueArr: [Int] = [1, 2, 3, 4]
let refArr: [Point] = [Point(), Point()]
valueArr[0] = -1 // error
refArr[0] = Point() // error
refArr[0].x = 1
let valueDict: [Int : Int] = [1: 1, 2: 2]
let refDict: [Int: Point] = [1: Point(), 2: Point()]
valueDict[1] = -1 //error
refDict[1] = Point() //error
refDict[1]!.x = -1

Related

Array with multiple values per index?

I'm learning swift, and I do the sololearn course to get some knowledge, but I bumped into something that I don't understand.
It is about modifying an array's values. The questionable part states the following:
In the following example, the elements with index 1, 2, 3 are replaced with two new values.
shoppingList[1...3] = [“Bananas”, “Oranges”]
How can an one dimensional array take more than one value per index? And how do I access them? Am I misunderstanding something?
What this code does is replacing the element of shoppingList in the 1...3 range using Array.subscript(_:)
That means considering this array:
var shoppingList = ["Apples", "Strawberries", "Pears", "Pineaples"]
that with:
shoppingList[1...3] = ["Bananas", "Oranges"]
Strawberries, Pears and Pineaples will be replaced by Bananas and Oranges.
so the resulting array will be: Apples, Bananas, Oranges
When you assign to a range of indices in an array (array[1...3]), those elements are removed from the array and the new elements are 'slotted in' in their place. This can result in the array growing or shrinking.
var array = Array(0...5)
// [0, 1, 2, 3, 4, 5]
array[1...3] = [-1, -2]
// [0, -1, -2, 3, 4]
Notice how our array's length is now one element shorter.
You could use a tuple (Value, Value), or create a struct to handle your values there, in fact if you plan to reuse this pair or value, a struct is the way to go.
By the way, there's no need to add [1..3], just put the values inside the brackets.
struct Value {
var name: String
var lastName: String
}
let values = [Value(name: "Mary", lastName: "Queen"), Value(name: "John", lastName: "Black")]
// Access to properties
let lastName = values[1].lastName
// OR
let tuples = [("Mary", "Queen"), ("John", "Black")]
let lastNameTuple = tuples[1].1
Hope you're enjoying Swift!

Append whole row to 2d array

I'm trying to append a whole row to data .. the full example is actual a dict of 2d arrays:
1> var a: [String:[[Double]]] = [:]
a: [String : [[Double]]] = 0 key/value pairs
2> a["a"] = []
3> a["a"].append([0.1, 0.2])
error: repl.swift:3:2: error: value of type '[[Double]]?' has no member 'append'
a["a"].append([0.1, 0.2])
~^~~~~ ~~~~~~
How do I get ["a":[[0.1, 0.2], [0.2, 0.3]]]
given that I will not know in advance what the key "a" is, nor the count of rows nor their values, until various later points in execution?
Since a["a"] returns an optional (because there might not be the key "a" in the dictionary), you need to use a["a"]?.append([0.1, 0.2]).
Another option is to provide a default:
a["a", default: []].append([0.1, 0.2])
This even eliminates the need for the a["a"] = [] line.
The reason you’re getting the error is you’re trying to append to an optional. Change it to a[“a”]?.append([0.1, 0.2])
For the expected output you would do
var a: [String: [[Double]]] = [:]
a["a"] = []
a["a"]?.append([0.1, 0.2])
a["a"]?.append([0.2, 0.3])
And another way to do it
var a: [String: [[Double]]] = [:]
a["a"] = [[0.1, 0.2], [0.2, 0.3]]

Swift lazy subscript ignores filter

How does subscripting a lazy filter work?
let ary = [0,1,2,3]
let empty = ary.lazy.filter { $0 > 4 }.map { $0 + 1 }
print(Array(empty)) // []
print(empty[2]) // 3
It looks like it just ignores the filter and does the map anyway. Is this documented somewhere? What other lazy collections have exceptional behavior like this?
It comes down to subscripting a LazyFilterCollection with an integer which in this case ignores the predicate and forwards the subscript operation to the base.
For example, if we're looking for the strictly positive integers in an array :
let array = [-10, 10, 20, 30]
let lazyFilter = array.lazy.filter { $0 > 0 }
print(lazyFilter[3]) // 30
Or, if we're looking for the lowercase characters in a string :
let str = "Hello"
let lazyFilter = str.lazy.filter { $0 > "Z" }
print(lazyFilter[str.startIndex]) //H
In both cases, the subscript is forwarded to the base collection.
The proper way of subscripting a LazyFilterCollection is using a LazyFilterCollection<Base>.Index as described in the documentation :
let start = lazyFilter.startIndex
let index = lazyFilter.index(start, offsetBy: 1)
print(lazyFilter[index])
Which yields 20 for the array example, or l for the string example.
In your case, trying to access the index 3:
let start = empty.startIndex
let index = empty.index(start, offsetBy: 3)
print(empty)
would raise the expected runtime error :
Fatal error: Index out of range
To add to Carpsen90's answer, you run into one of Collection's particularities: it's not recommended, nor safe to access collections by an absolute index, even if the type system allows this. Because the collection you receive might be a subset of another one.
Let's take a simpler example, array slicing:
let array = [0, 1, 2, 3, 4]
let slice = array[2..<3]
print(slice) // [2]
print(slice.first) // Optional(2)
print(slice[0]) // crashes with array index out of bounds
Even if slice is a collection indexable by an integer, it's still unsafe to use absolute integers to access elements of that collection, as the collection might have a different set of indices.

Cannot assign sorted array to a variable in Swift [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
I'm trying to sort one array and assign it to the other. Both arrays are identically defined like so:
var arrayA: [String: [Int]] = [:]
var sortedArrayA:[String: [Int]] = [:]
sortedArrayA = arrayA.sort{ $0.0 < $1.0 } // error on this line.
I am gettin this error:
Cannot assign value of type [(String, [Int])] to type [String : [Int]]
What I'm trying to achieve is to make this dictionary:
["c" : [1,2,3], "a" : [2,3,3], "b" : [4,4,4]]
sorted like this:
["a" : [2,3,3], "b" : [4,4,4], "c" : [1,2,3]]
If it makes sence.
Yeah, I know closures in Swift are cool. But they are not cool enough to infer that you want to sort an array from this code:
var arrayA: [Int] = []
var sortedArrayA:[Int] = []
sortedArrayA = arrayA{ $0 < $1 }
And your code is even worse! You didn't even declare arrays! What you declared are dictionaries which are supposed to not be sorted!
Anyway, just learn the syntax of arrays: it's a pair of square brackets surrounding the type of array you want. So an array of Ints will be [Int] and an array of Strings will be [String].
Got it? Cool.
"But I only have dictionaries, though..." you said sadly. If you only have dictionaries, you can either sort its keys or values. I think you probably need to sort the values.
let values = someDictionary.values // if you want to sort keys, use .keys instead
Now you need to actually call the sort method in order to sort. Just writing a closure is not going to work.
let sortedValues = values.sort(<)
You can do this with any arrays of course!
let array = [3, 2, 1]
let sortedArray = array.sort(<)
In your question you say that you use array but actually you are using dictionaries. And your syntax for this is wrong. you can declare empty dictionary like this: var dictionary: [String:Int] = (). But to answer your real question you can achieve it like this:
let arrayA = ["c" : [1,2,3], "a" : [2,3,3], "b" : [4,4,4]]
let sortedDict = arrayA.sort { $0.0 < $1.0 }
print("\(sortedDict)")
Try and figure out the array sorting in Playground, in swift you can just use .sort() to sort the array. For example, for array of integers:
var array = [Int]() //initial empty array
array = [2, 1, 4, 3]
array = array.sort() // array is now sorted

Adding Values In Dictionary With Swift

I have this Dictionary:
var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
and I want to add the values for example to have the result as 30 , how can I do that? In other words, how can I only add the numbers, not the words?
Since an answer has been accepted and it isn't a very good one, I'm going to have to give up on the socratic method and show a more thematic way of answering this question.
Given your dictionary:
var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
You get the sum by creating an array out of the dict.values and reducing them
let sum = Array(dict.values).reduce(0, +)
Or you could use the bare form of reduce which doesn't require the array to be created initially:
let sum = reduce(dict.values, 0, +)
Or the more modern version, since reduce is defined on an Array
let sum = dict.values.reduce(0, +)
The accepted answer doesn't use the power of swift
and the answer that does is outdated.
The simplest updated solution is:
let valuesSum = dict.values.reduce(0, +)
start with zero, and sum the values of all the elements
As explained in the documentations here. You access and modify a dictionary through its methods and properties, or by using subscript syntax. Read the doc.
var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
To access a value in your dictionary you can use the subscript syntax:
if let cola = dict["cola"] as? Int { // to read the value
// Do something
}
dict["cola"] = 30 // to change the value
dict["pepsi"] = 25 // to add a new entry to your dictionary
dict["fanta"] = nil // to delete the fanta entry.
to read all the value in your dictionary
var sum = 0
for (drinkName, drinkValue) in dict {
println("\(drinkName): \(drinkValue)")
sum += drinkValue
}
or you can
var sum = 0
for drinkValue in dict.values {
sum += drinkValue
}