Adding Values In Dictionary With Swift - 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
}

Related

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.

Swift: Working with for and array

I started to learn Swift but I have some problems like I want to sum two arrays and put them in a third array and I have to do it with for loop.
var ar1 = [1,3,5,7,9]
var ar2 = [2,4,6,8,10]
var ar3 : [Int] = [5]
for i in 0... ar1.count-1 {
// for loop for index
ar3[i] = ar1[i] + ar2[i]
}
But I get an out of range error. I tried a lot but I could not solve it.
Your code looks more like C or Java than swift, but you're on the right track. There are many other ways to do this, but this code is very similar to what you were trying to do:
func example() {
let array1 = [1, 3, 5, 7, 9]
let array2 = [2, 4, 6, 8, 10]
var array3 = [Int]()
for i in 0 ..< array1.count {
array3.append(array1[i] + array2[i])
}
for element in array3 {
print("\(element)")
}
}
Use "let" if the variable never changes once you defined it.
I added a loop at the bottom so you can verify the results, and also so you can see that you don't need "i" in loops.

Reduce to count elements in a dictionary in Swift

I'm trying to count the elements of my dictionary. The dictionary is of type [EKCalendar: ReminderList] where ReminderList is a class with a list property. I want to go through the dictionary and add up the count of all these lists.
My dictionary is in the property self?.reminderListsStructure.structure.
let numberOfElements = self?.reminderListsStructure.structure.reduce(0) {
accumulator, nextValue in
return accumulator.list.count + nextValue.list.count
// COMPILE ERROR: Type of expression is ambiguous without more context
}
let count = reminderListsStructure.structure.reduce(0) { $0 + $1.1.list.count }
Something like this. Not enough info though, so I'm not 100% sure it works.
I think flatMap is a more appropriate choice here:
let input = [
1: [1],
2: [1, 2],
3: [1, 2, 3],
4: [1, 2, 3, 4],
5: [1, 2, 3, 4, 5]
]
let output = input.values.flatMap{$0}.count //15
When you reduce a dictionary, the element type is a tuple of the Key and Value types, so you can use:
dictionary.reduce(0) { $0 + $1.1.list.count }
Or, you can get just the values from the dictionary and reduce that:
dictionary.values.reduce(0) { $0 + $1.list.count }
Note that since Dictionary.values returns a lazy iterator, there's not really a huge cost to using it.
More simple and clear way goes like this,
var dict = ["x" : 1 , "y" : 2, "z" : 3]
let count = dict.reduce(0, { x, element in
//maybe here some condition
//if(element.value > 1){return x}
return x + 1
})

How to Multiply Every Value in a Dictionary in Swift

So, currently I have this dictionary:
var data : [Int:Float] = [0:0,1:1,2:1.414,3:2.732,4:2,5:5.236,6:3.469,7:2.693,8:5.828,9:3.201]
I want to create a new dictionary, say "newData." I want "newData" to have the same keys as "data," but I want to multiply every value in "data" by some constant (say "multiple") to get the values in "newData." How can I do this?
Thanks!
var newData = data
for (key, value) in newData
{
newData[key] = value * multiple
}
Given
let data : [Int:Float] = [0:0,1:1,2:1.414,3:2.732,4:2,5:5.236,6:3.469,7:2.693,8:5.828,9:3.201]
let factor: Float = 2
You can use the reduce method
let multiplied = data.reduce([Int:Float]()) { (var result, elm) -> [Int:Float] in
result[elm.0] = elm.1 * factor
return result
}
The result.
[3: 5.464, 2: 2.828, 4: 4.0, 9: 6.402, 5: 10.472, 6: 6.938, 7: 5.386, 0: 0.0, 8: 11.656, 1: 2.0]
Please ignore the order since Dictionaries do not have one.
Why this solution is better then a for loop?
The code I am suggesting here does follow the Functional Programming paradigm. There are several advantages over the classic for loop:
It's thread safe: since only immutable values are used, you don't have to worry about other threads that could change these values while you are using them.
It's faster: under the hood the elements of the results are processed in parallel
It's less error prone because it's more declarative: we are describing how the result should be, not how to build it.
Another solution based on map
let dict1 = ["a":1, "b":2, "c":3]
// Make a copy since we don't want to modify the original
var dict2 = dict1
let multiple = 5
dict2.map { (k,v) in dict2[k] = v*multiple }
I did some simple performance testing with a 10000 and 100000 element array the various solutions proposed perform like this
For Loop: 10000 elements 1.28 ms, 100000 elements 12.28 ms
Map(): 10000 elements 1.24 ms, 100000 elements 12.23 ms
Reduce(): 10000 elements 2.36 ms, 100000 elements 17.18 ms
But you don't have a 10000+ element array. It's just worth noting the difference.
Since Swift 4, Dictionary has a property called mapValues(_:). mapValues(_:) has the following declaration:
Returns a new dictionary containing the keys of this dictionary with the values transformed by the given closure.
func mapValues<T>(_ transform: (Value) throws -> T) rethrows -> Dictionary<Key, T>
The Swift 5 Playground sample code below shows how to use mapValues(_:) in order to create a new dictionary by multiplying every value of an existing dictionary:
let multiple: Float = 2
let data: [Int : Float] = [0 : 0, 1 : 1, 2 : 1.4, 3 : 2.7, 4 : 2, 5 : 5.2]
let newData = data.mapValues { (value: Float) -> Float in
return value * multiple
}
//let newData = data.mapValues { $0 * multiple } // also works
print(newData) // [3: 5.4, 4: 4.0, 2: 2.8, 0: 0.0, 1: 2.0, 5: 10.4]

Immutable Dictionary value change

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