adding doubles contained within a dictionary swift 3 - swift

I am learning a little bit about Swift and am following along with a Udemy course. The course is taught in swift 2 and I am using swift 3 so I am hoping to understand the difference in outputs and I cannot find any answer online thus far.
I have a dictionary item which contains 3 things.
var menu = ["entre" : 5.55, "main-meal": 20.50, "desert": 5.50]
The idea is to add the 3 values together using the instructors output (which works fine in swift 2):
var totalCost = menu["entre"]! + menu["desert"]! + menu["main-meal"]!
Within the course this works just fine but for me it throws an error that reads "Cannot subscript a value of type 'inout [String : Double]' (aka 'inout Dictionary')"
What I find very odd is that if I only use 2 values, all is fine, the problem is when the third is added. I can get around the issue by adding + 0.0 to the end as below:
var totalCost = menu["entre"]! + menu["desert"]! + menu["main-meal"]! + 0.0
What I am hoping to understand is what is the difference between the two versions and ideally what I am doing wrong in adding the 3 together without my workaround.
Thanks in advance.

Workarounds
For a few keys
let (entreCost, desertCost, mainCost) = (menu["entre"]!, menu["desert"]!, menu["main-meal"]!)
let totalCost = entreCost + desertCost + mainCost
For a lot of keys
let keysToSum = ["entre", "desert", "main-meal"]
keysToSum.map{ menu[$0]!}.reduce(0, +)
For all keys
menu.values.reduce(0, +)

Related

Ordering of Dictionary Swift

I'm trying to work through a problem at the moment which is currently doing the rounds on the internet. The problem is: Given an array of characters, find the first non repeating character. I had a go at it and solved it but I was curious about how other people solved it so I did some looking around and found this answer:
let characters = ["P","Q","R","S","T","P","R","A","T","B","C","P","P","P","P","P","C","P","P","J"]
var counts: [String: Int] = [:]
for character in characters {
counts[character] = (counts[character] ?? 0) + 1
}
let nonRepeatingCharacters = characters.filter({counts[$0] == 1})
let firstNonRepeatingCharacter = nonRepeatingCharacters.first!
print(firstNonRepeatingCharacter) //"Q"
Source: Finding the first non-repeating character in a String using Swift
What I don't understand about this solution, is why it always returns Q, when there are other elements "S" "A" "B" and "J" that could be put first when the filter is applied to the dictionary. My understanding of dictionaries is that they are unordered, and when you make one they change from run to run. So if I make one:
let dictionary:[String:Int] = ["P": 9, "C": 8, "E": 1]
And then print 'dictionary', the ordering will be different. Given this, can anyone explain why the solution above works and maintains the order in which the dictionary elements were added?
You are not looking correctly at the code. The filter is not applied to a dictionary. It is applied to the array (characters), which has a defined order. The dictionary is used only to store counts.

Data ranged subscribe strange behavior

I was playing with swift's Data in the following a small code:
var d = Data(count: 10)
d[5] = 3
let d2 = d[5..<8]
print("\(d2[0])")
To my surprise, this code throws exception on print() while the following code does not:
var d = Data(count: 10)
d[5] = 3
let d2 = d.subdata(in: 5..<8)
print("\(d2[0])")
I somehow understand why this happens, but I don't get why this is designed like this. When I use subdata() I get a whole copy of range, so indexing is valid from 0. But when I use range subscribe [], I get access to the requested range while indexing is the same as before. So in my first example d2[5] is 3.
But I wonder why it is designed like this? I don't want to make a copy of my data by using subdata() method. I just wanted to access a portion of my data with better indexing.
This is especially creates unexpected behaviors if you pass it to a function. For example, following code creates unexpected results and exceptions and you may not find out easily why:
func testit(idata: Data) {
if idata.count > 0 {
print("\(idata.count)")
print("\(idata[0])")
}
}
//...
var d = Data(count: 10)
d[5] = 3
let d2 = d[5..<8]
testit(idata: d2)
This code is really strange. Because if you debug your code, you see that print("\(idata.count)") prints 3 as size of idata which is correct, but accessing it with idata[0] creates exception.
Is there any reason for this design? I was expecting that I could access resulting Data from subscribe starting index 0 while it is not true. Can I do this without using subdata() which creates copy of data or using additional arguments to pass base of data slice?
d[5..<8] returns Data.Slice – which happens to be Data. Generally, slices share the indices with their base collection, as documented in Slice.
One possible reason for this design decision is that it guarantees that subscripting a slice is a O(1) operation (adding an offset for accessing the base collection is not necessarily O(1), e.g. not for strings.)
It is also convenient, as in this example to locate the text after the second occurrence of a character in a string:
let string = "abcdefgabcdefg"
// Find first occurrence of "d":
if let r1 = string.range(of: "d") {
// Find second occurrence of "d":
if let r2 = string[r1.upperBound...].range(of: "d") {
print(string[r2.upperBound...]) // efg
}
}
As a consequence, you must never assume that the indices of a collection are zero-based (unless documented, as for Array.startIndex). Use startIndex to get the first index, or first to get the first element.

What's faster/should be rather used for short(ish) Strings: Split or Substring?

Swift 5, Xcode 10.
I'm looping through an array of Strings (size probably < 20), each of them looks something like this:
johnsmith.20190202102030.conf
janedoe.19700101115959.conf
I know the first part (the name) beforehand but want to extract the middle part (birthday: 8, 12 or 14 characters long).
Version 1:
let f = "johnsmith.20190202102030.conf"
let name = "johnsmith"
let start = f.index(f.startIndex, offsetBy: name.count+1)
let end = f.index(f.startIndex, offsetBy: f.count-5)
let birthday = String(f[start..<end])
Version 2:
let f = "johnsmith.20190202102030.conf"
let farr = f.split(separator: ".").map(String.init)
let birthday = farr[1]
I'm currently only doing this for 10 Strings and (of course) didn't notice any difference in speed. Even with 100 Strings there probably won't be much of a difference anyway but I'm curious:
Ignoring the length of the code and potential errors, is there a reason (apart from personal preference) to prefer using one version over the other (e.g. speed with 100k Strings - I'm not asking for actual measurements!)?
From my very rough testing, it seems that the substring version is faster. However, in your case I would opt for using the version using split. The code is much more readable to me.

Display certain number of letters

I have a word that is being displayed into a label. Could I program it, where it will only show the last 2 characters of the word, or the the first 3 only? How can I do this?
Swift's string APIs can be a little confusing. You get access to the characters of a string via its characters property, on which you can then use prefix() or suffix() to get the substring you want. That subset of characters needs to be converted back to a String:
let str = "Hello, world!"
// first three characters:
let prefixSubstring = String(str.characters.prefix(3))
// last two characters:
let suffixSubstring = String(str.characters.suffix(2))
I agree it is definitely confusing working with String indexing in Swift and they have changed a little bit from Swift 1 to 2 making googling a bit of a challenge but it can actually be quite simple once you get a hang of the methods. You basically need to make it into a two-step process:
1) Find the index you need
2) Advance from there
For example:
let sampleString = "HelloWorld"
let lastThreeindex = sampleString.endIndex.advancedBy(-3)
sampleString.substringFromIndex(lastThreeindex) //prints rld
let secondIndex = sampleString.startIndex.advancedBy(2)
sampleString.substringToIndex(secondIndex) //prints He

Increment number in Dictionary

I have a Dictionary [String:AnyObject] which contains some keys and values.
I want to increment a key to which value is of type Double.
I can do it this way:
let nr = dict["number"] as! Double
dict["number"] = nr + 10
But I dont like that way so Im wondering if there is another way
I tried this:
(dict["number"] as! Double) += 10
But that gives me an error:
Binary operator '+=' cannot be applied to operands of type '(Double)' and 'Double'
Why isn't this working?
Following is an alternative. If you want to avoid force unwrapping an optional:
dict["number"] = (dict["number"] ?? 0) + 10
You are close and in fact you can write to a dictionary using +=, the problem is your cast. For example we can do:
var dict = ["number" : 2]
dict["number"]! += 10
and now dict["number"] returns 12. Now this is creating a new value (12) and replacing it into the dictionary, it is just a clean way of looking at it.
The problem with your code is that the left side (dict["number"] as! Double) gives you a Double. So you have say (12), then the right side is a Double too (10). So your code ends up looking like (12) += 10 which you can clearly see as problematic, since this is equivalent to 12 = 12 + 10, yikes!
So that being said, you can use the my first solution if you are working with native Swift dictionaries, otherwise your solved solution above works too, just a bit longer.
Lastly, if you are really looking for a one liner that works with your exact situation you should be able to do something like:
dict["number"] = (dict["number"] as! Double) + 10
Another option:
dict["number", default: 0] += 10
The safe way of casting would be:
if let num = dict["number"] as? Double {
dict["number"] = num + 10
}