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]
Related
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]
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.
I have an array of dictionaries called arrayOfDict which contains a number of dictionary objects all with the same keys: QUESTIONID and OPTIONID.
[ //arrayOfDict
{QUESTIONID:1, OPTIONID:0},
{QUESTIONID:2, OPTIONID:201},
{QUESTIONID:3, OPTIONID:204)
];
I need to add such dictionaries to arrayOfDict only if the dictionary I am adding does not contain the same QUESTIONID. If the QUESTIONID already exists then the corresponding OPTIONID needs to be replaced with new one. How can I compare my QUESTIONID with the QUESTIONID in arrayOfDict ?
you can try to get the index of the same question dic, if you get it, remove, else just insert it, try this:
if let index = array.index(where: {$0["QUESTIONID"] == dic["QUESTIONID"]}) {
array.remove(at: index)
}
array.append(dic)
Please check :
var dict = arrayOfDict.map { dictionary -> ([String : Int]) in
var dicti = dictionary
if dicti["QUESTIONID"] == 1 { // You can change 1 with whatever `QUESTIONID` you want to check
dicti["OPTIONID"] = 1 // You can change 1 with whatever value you want to assign for `OPTIONID`
}
return dicti
}
print(dict)
I'm trying to implement a groupBy functionality where all the numbers of a nested list are grouped. My code so far:
struct MyClass {
var numbers: [Int]
...
}
var dict: [String : MyClass] = ...
let numbers = dict
.filter{ $0.0.containsString(searchString) }
.flatMap{ $0.1.numbers }
This yields me an Array of Ints. However I'd like to have a dictionary [Int : Int] with each unique number and the count of its occurence. So for example:
[1,2,3,4,1,2,2,1]
should be:
[1 : 2, 2 : 3, 3 : 1, 4 : 1]
I know there's a groupBy operator, but Swift doesn't seem to have one. I've tried with reduce:
func reducer(accumulator: [Int: Int], num: Int) -> [Int : Int] {
var acc = accumulator
acc[num]! += 1
return acc
}
filtered.reduce([:], combine: reducer)
But it crashes when I want to run it. Not sure why, I get a EXC_BAD_INSTRUCTION.
I'd appreciate any help.
let numbers = [1,2,3,4,1,2,2,1]
var results = [Int: Int]()
Set(numbers).forEach { number in results[number] = numbers.filter { $0 == number }.count }
print(results) // [2: 3, 3: 1, 1: 3, 4: 1]
Actually I'm not very sure if this is what you want. I just looked at your examples.
Using NSCountedSet:
var objects = [1,2,3,4,1,2,2,1]
let uniques = NSCountedSet(array: objects)
uniques.forEach { results[$0 as! Int] = uniques.countForObject($0) }
print(results) // [2: 3, 3: 1, 1: 3, 4: 1]
I would expect the crash to be ocurring on this line:
acc[num]! += 1
The first time this is called for a number, the entry doesn't exist in the dictionary yet so acc[num] is nil. Forcefully unwrapping it would cause a crash.
Not sure if this is the best solution but you can simple check for this case:
if (acc[num]) {
acc[num]! += 1
} else {
acc[num] = 1
}
Cleaner code from #vacawama in the comments:
acc[num] = (acc[num] ?? 0) + 1
Here's an extension to Array that does what you're asking:
extension Array where Element: Hashable {
var grouped: [Element:Int] {
var dict = [Element:Int]()
self.forEach { dict[$0] = (dict[$0] ?? 0) + 1 }
return dict
}
}
The key is the closure: { dict[$0] = (dict[$0] ?? 0) + 1 }.
It takes the current value in the array, tests to see if it's a key in the dictionary, returns the value for that key if it exists or 0 if it doesn't, then adds one and sets the key:value to be the pair of the current value and occurrences so far.
Example use:
[1,2,3,4,1,2,2,1].grouped // => [2: 3, 3: 1, 1: 3, 4: 1]
You need something like this:
if let _ = acc.indexForKey(num) {
acc[num]! += 1
}
else {
acc[num] = 1
}
It's sort of unclear what you're asking for, but here's a function that will take an array of ints and return a dictionary with the number as the key, and the count as the value:
func getDictionaryOfCounts(accumulator: [Int]) -> [Int : Int] {
var countingDictionary: [Int : Int] = [:]
accumulator.forEach { (value) in
if countingDictionary[value] != nil {
countingDictionary[value]! += 1
}
else{
countingDictionary[value] = 1
}
}
return countingDictionary
}
1) this is first step : I'm asking how to make this dictionary in order by value.
2)second step: I want to split this dictionary in two array, one for value and one for keys thanks
["fruit": 1, "vegie": 13, "money": 46, "Canada": 219, "cash": 1, "lola": 1, "tv": 2, "bed": 1, "sofa": 1]
I did something like that but I want to split in two arrays now
let byValue = {
(elem1:(key: String, val: Int), elem2:(key: String, val: Int))->Bool in
if elem1.val < elem2.val {
return true
} else {
return false
}
}
let sortedDict = dict.sort(byValue)
Assuming that the part 1 of your question is done as you said in your last edit, here is how to have...
The keys:
let keys = sortedDict.map { $0.0 }
And the values:
let values = sortedDict.map { $0.1 }