Is there any catchall in swift? - swift

I have varying input that will be a String like:
"James"
"James(1)"
"James(2)"
I'm looking to insert the values for these keys into a dictionary only after I remove the (x)
What can I use to represent x to then remove the entire parenthesis?
My current attempt looks like this:
replacingOccurrences(of: "(\((Any).self)", with: "")
But that's not working..
Desired output would be a dictionary only containing the one unique value as the key.
So with the input of
["James" : 3, "James(1)" : 3, "James(2)" : 4, "Sarah" : 10, "Sarah(1)" : 10, "Sarah(2)" : 10 ]
I would get this output
["James" : 10, "Sarah" : 30]

I like George's solution, but I think this is a nice use case for uniquingKeysWith:.
// Convert to [(name, value)], removing everything after "("
let keyValues = data.map { k, v in (String(k.prefix(while: { $0 != "(" })), v) }
// Sum matching values
let result = Dictionary(keyValues, uniquingKeysWith: +)

Easiest way would be to use reduce(into:_:).
It works by:
Starting with an empty dictionary to create in the reduce.
Get index of first bracket/parenthesis (nil if none)
Get the name excluding anything after the (. Otherwise take whole name.
Append the value from the input for the current key as the name. If the name doesn't exist yet, default value of 0 is given.
Code:
let input = ["James": 3, "James(1)": 3, "James(2)": 4, "Sarah": 10, "Sarah(1)": 10, "Sarah(2)": 10]
let output: [String: Int] = input.reduce(into: [:]) { partialResult, pair in
let firstBracket = pair.key.firstIndex(of: "(")
let basicName = String(pair.key.prefix(upTo: firstBracket ?? pair.key.endIndex))
partialResult[basicName, default: 0] += pair.value
}
print(output)
// Prints: ["James": 10, "Sarah": 30]

Related

Get all values into dictionary and create a String with a specific format

I have a dictionary with this structure:
a: [1,2]
b: [3,4]
c: [5,6]
and I need to return a string with this structure.
a,b,c\n1,3,5\n2,4,6
I solved the first part of the string. But to get the rest of the String. I try to iterate into my dictionary to get the first elements for each key in my dictionary and then get the rest for each value into the array.
Is there an easier way to get this?
Once you know what's the order of the keys (alpha ?), you can use this:
let dict: [String: [Int]] = ["a": [1,2], "b": [3, 4], "c": [5, 6]]
let keys = dict.keys.sorted() //Or do whatever you want here to get your target order
var matrix: [[String]] = []
keys.forEach {
guard let arrayAsInt = dict[$0] else { return }
let arrayAsString = arrayAsInt.map{ "\($0)" }
matrix.append( [$0] + arrayAsString)
}
print("Matrix: \(matrix)")
let transposed = matrix.transposed()
print("Transposed Matrix: \(transposed)")
let output = transposed.map { $0.joined(separator: ",")}.joined(separator: "\n")
print(output)
The outputs:
$>Matrix: [["a", "1", "2"], ["b", "3", "4"], ["c", "5", "6"]]
$>Transposed Matrix: [["a", "b", "c"], ["1", "3", "5"], ["2", "4", "6"]]
$>a,b,c
1,3,5
2,4,6
Obvisouly the "\n" might be invisible and be an actual new line
a,b,c
1,3,5
2,4,6
Being
a,b,c\n1,3,5\n2,4,6
What's the idea behind that? Create a matrix and use the transpose (it's used in maths with matrix, it's one of the basic modification of a matrix).
First transform the [String: [Int]] into a [[String]], where each element would be key followed by its values. I transformed it there as String for simpler code later.
Why doing that? Because the matrix value is easy to get from your initial dict. the transposed value is harder (not impossible) to get from dict but easier from matrix, and the transposed is quickly transformed into your format.
So my thinking was the reverse:
Get a structure from your output, then how to get it, it's a transpose, so I need to get the initial input as it, etc.
With the help of a code for Transpose Matrix (that accept String elements).
extension Collection where Self.Iterator.Element: RandomAccessCollection {
// PRECONDITION: `self` must be rectangular, i.e. every row has equal size.
func transposed() -> [[Self.Iterator.Element.Iterator.Element]] {
guard let firstRow = self.first else { return [] }
return firstRow.indices.map { index in
self.map{ $0[index] }
}
}
}
Any code (there a various) working ones, should the trick. I took it from here.
As pointed by #Leo Dabus, you can remove the Self.Iterator.Element
from the extension code (twice). I just wanted to it as such, not modifying the initial answer since it's not mind.
What you are looking for, besides composing the final string, is how to transpose a collection (this would work with collections of different sizes as well):
extension Sequence {
func max<T: Comparable>(_ predicate: (Element) -> T) -> Element? {
self.max(by: { predicate($0) < predicate($1) })
}
}
extension Collection where Element: RandomAccessCollection, Element.Indices == Range<Int> {
func transposed() -> [[Element.Element]] {
(0..<(max(\.count)?.count ?? .zero)).map {
index in compactMap { $0.indices ~= index ? $0[index] : nil }
}
}
}
let dict = ["a": [1,2,3],
"b": [4,5,6],
"c": [7,8,9]]
let sorted = dict.sorted(by: {$0.key < $1.key})
let result = sorted.map(\.key).joined(separator: ",") + "\n" +
sorted.map(\.value).transposed().map {
$0.map(String.init).joined(separator: ",")
}.joined(separator: "\n")
result // "a,b,c\n1,4,7\n2,5,8\n3,6,9"
A dictionary is an unordered collection so you need to sort it according to any specific key. Here I sort the dictionary according to the key if you don't care about an order you can just remove sort.
let dict: [String: Any] = ["a": [1,2], "b": [3,4], "c": [5,6]]
let sortedKey = dict.keys.sorted(by: <)
let key = sortedKey.joined(separator: ",")
var firstValues: [String] = []
var secondValues: [String] = []
sortedKey.forEach { (key) in
if let dictValue = dict[key] as? [Int],
let firstValue = dictValue.first,
let secondValue = dictValue.last {
firstValues.append("\(firstValue)")
secondValues.append("\(secondValue)")
}
}
let finalString = key + "\n" + firstValues.joined(separator: ",") + "\n" + secondValues.joined(separator: ",")
print(finalString) // "a,b,c\n1,3,5\n2,4,6"

How can I prevent or stop dictionary values from being nill?

I have a dictionary and a array of strings
The keys and values are generated with for loop
for some reason , all values in dictionary are nill.
Create a empty dictionary
Create a string array
Create for loop to generate keys and values
keys become i.e. KEY_15.
values would be a random number
Create for loop to check if the dictionary contains any of the elements in the array
For each existing key that matches arr element, check if that key value is even or not i.e if(arr[0] == dictionary key)
if even, change dictionary value to 0 i.e. if arr contains element with string "Key_12" and dictionary contains a key with the name "Key_12", then value becomes 0.]
Making 2 for loops to match but problem still occurs
//Code Starts Here
var arr : [String] = ["KEY_10", "Bear", "KEY_23", "KEY_12"] // string array
var dic: [String : Int] = [:] //default dic
let ran: Int? = Int.random(in: 0...10) //generate random value
for i in 10...24{ //create elements to dic
let iAsString = String(i)
let stringWithZero = "KEY_" + iAsString
dic[stringWithZero] = ran!
}
for x in arr{
let dickeys: [String] = [String](dic.keys) //store keys
let element = x
for y in 0...dickeys.count-1{
let dicKey = dickeys[y]
if dicKey == element{ //never runs
if dic[x]! % 2 == 0{
dic.updateValue(0, forKey: x) //update value to 0
}
}
}
}
Your code works, but it isn't efficient.
Here is a cleaned up version:
var arr = ["KEY_10", "Bear", "KEY_23", "KEY_12"] // string array
var dic: [String : Int] = [:] //default dic
for i in 10...24 { //create elements to dic
dic["KEY_\(i)"] = Int.random(in: 0...10)
}
print(dic)
for x in arr {
if let value = dic[x] {
if value % 2 == 0 {
dic[x] = 0
}
}
}
print(dic)
Output:
["KEY_19": 2, "KEY_22": 5, "KEY_11": 7, "KEY_21": 3, "KEY_15": 8, "KEY_14": 6, "KEY_12": 6, "KEY_17": 9, "KEY_23": 3, "KEY_16": 1, "KEY_18": 1, "KEY_24": 4, "KEY_10": 0, "KEY_13": 8, "KEY_20": 1]
["KEY_19": 2, "KEY_22": 5, "KEY_11": 7, "KEY_21": 3, "KEY_15": 8, "KEY_14": 6, "KEY_12": 0, "KEY_17": 9, "KEY_23": 3, "KEY_16": 1, "KEY_18": 1, "KEY_24": 4, "KEY_10": 0, "KEY_13": 8, "KEY_20": 1]
Notes:
You should move the generation of the random Int into the first loop so that each key potentially gets a different random value.
Let Swift infer types wherever possible (eg. use var array = ["KEY_10"] instead of var array: [String] = ["KEY_10"]).
Use string interpolation to create "KEY_10" through "KEY_24".
To check if a key exists in a dictionary, just look it up. There is no need to loop over all of the keys of the dictionary. The value returned is an optional that is nil if the key doesn't exist. Use optional binding to unwrap that value.
if let value = dic[x] {
// we only get here if key x exists
// value is then the unwrapped value corresponding to key x
}
dic.updateValue(0, forKey: x) is better written as dic[x] = 0.

How do i init dictionary with range of keys in swift?

Here is a swift dictionary declaration:
var cardField = [Int:Card]()
How can i init a keys for this dictionary, using range syntax?
Something like that:
var cardField: [Int:Card] = [0...5:nil]
This is doesn't work...
Thank you.
Unfortunately, Range isn't a Sequence, so it can't be directly passed to reduce(into:) stride is though, so you can use something like:
let cardField = Dictionary(uniqueKeysWithValues: stride(from: 0, to: 5, by: 1).map { ($0, "\($0)" )})
The biggest problem is you haven't specified what the value of the keys should be, so without that information we're really just poking in the dark.
You could create an array then add it to a dictionary:
var values = Array(1...5)
let keyToValue = Dictionary(uniqueKeysWithValues: zip(values, 1...5))
print(keyToValue[3]!)
// Prints 3
print(keyToValue)
// Prints [5: 5, 2: 2, 3: 3, 1: 1, 4: 4]

I need to create array with named index and search in it

I need to create an array with these info:
Fruits: Counts("apple":"14","orange":"3","grape":"6", ...)
And then search in it to see if we have any (fruit) indexed? and if not add it with 1 quantity, and if it exist, add 1 to its (counts)
Here you go -
var fruits:[String:Int] = ["apple":14,"orange":3,"grape":6]
let filtered = fruits.filter({$0.key.elementsEqual("apple")})
fruits["apple"] = (fruits["apple"] ?? 0) + 1
print(fruits["apple"])
At very first line you create a dictionary of your key and values.
in second line you filter the dictionary with the desired key which is in this case apple you can even make this key as variable and replace the apple with variable. In return of filter you get an array of filtered values with provided key. Now you simply check if the count of this is greater then 0, which means there exist a value for provided key. If it is there you increment it by one else you create a new value with the key.
var fruitCount : [String : Int] = ["apple" : 14, "orange" : 3, "grape" : 6];
func addFruit( FruitName name : String ) {
for (fruitName , count) in fruitCount {
if ( fruitName == name ) {
fruitCount[name]! += 1 // fruitCount[name] return optional(Int) so, unwrap force!
return
}
}
fruitCount[name] = 1
}
addFruit(FruitName: "apple")
addFruit(FruitName: "kiwi")
print(fruitCount)
We can see
["orange": 3, "apple": 15, "grape": 6, "kiwi": 1]

How to 'switch' based on keys contained in a dictionary in Swift?

I want to execute different branches based on what keys a dictionary contains, here's some code you can paste into a playground that shows what I currently do:
let dict1 = ["a" : 1, "thingy" : 2]
let dict2 = ["b" : 3, "wotsit" : 4]
let dict = dict1 // Change this line to see different outcomes
if let valueA = dict["a"],
let thingy = dict["thingy"] {
// Code for type with "a" and "thingy" keys
println("a/thingy")
} else if let valueB = dict["b"],
let wotsit = dict["wotsit"] {
// Code for type with "b" and "wotsit" keys
println("b/wotsit")
}
However, I think this would be more elegantly expressed as a switch statement - something like this:
let dict1 = ["a" : 1, "thingy" : 2]
let dict2 = ["b" : 3, "wotsit" : 4]
let dict = dict1 // Change this line to see different outcomes
switch dict {
case let a = dict["a"],
let thingy = dict["thingy"]:
// Code for type with "a" and "thingy" keys
println("a/thingy")
case let b = dict["b"],
let wotsit = dict["wotsit"]:
// Code for type with "b" and "wotsit" keys
println("b/wotsit")
default:
break
}
I have tried the above and various other attempts to express this logic in a switch but couldn't make it work. So how could I do this in a switch (or is this misguided in some way)?
Background:
The dictionaries are actually SwiftyJSON JSON objects loaded from JSON data, and I want to infer the 'type' of object these JSON structures represent, from what keys they contain - if they don't contain all the right keys for a particular object they won't attempt to load as that type. I could add a "type" to each JSON structure and switch based on that value, but I'd prefer to automatically infer their type from the keys as I currently do.