I have an array that describes a list of auto parts (Swift/IOS,array already in such structure arrived from other source.):
let parts = [
"Wheel = 230$",
"Door = 200$",
"Wheel = 300$",
"Seat = 150$",
"Seat = 150$",
"Rugs = 100$"]
I need to calculate the sum of the prices of the auto parts for each type of part. Here's the result I'm looking for:
let expectedResult = [
"wheel 530$",
"Door 200$",
"Seat 300$",
"Rugs 100$"
]
I don’t understand how to do it.
Here is a solution where I loop through the array and split each element on "=" and then sum the values together using a dictionary. Once that is done the dictionary is converted back to an array
let parts = [
"Wheel = 230$",
"Door = 200$",
"Wheel = 300$",
"Seat = 150$",
"Seat = 150$",
"Rugs = 100$"]
var values = [String: Int]() // Used to calculate totals per part
parts.forEach { string in
let split = string.split(separator: "=")
// Make sure the split worked as expected and that we have an integer value after the =
guard split.count == 2,
let value = Int(String(split[1]).trimmingCharacters(in: .whitespaces).dropLast()) else { return }
let key = String(split[0]).trimmingCharacters(in: .whitespaces)
// Sum values over the part name
values[key, default: 0] += value
}
// Convert back to an array of strings
let output = values.map { "\($0.key) \($0.value)$"}
print(output)
Related
I had two Arrays.
let quntityArr = ["1","3","4","7"]
let priceArr = ["£129.95", "£179.95","£169.95","£199.85"]
I want to multiply these both Arrays in the following way
let totalArr = ["1*£129.95", "3*£179.95", "4*£169.95", "7*£199.85"]
Here I want to calculate each price with those product quantities.
You need
let quntityArr:[Double] = [1,3,4,7]
let priceArr = [129.95, 179.95,169.95,199.85]
let totalArr = zip(quntityArr, priceArr).map { "£\($0 * $1)" }
print(totalArr)
Assuming your input data is provided as array of String.
1. Input Data
let quntityArr = ["1","3","4","7"]
let priceArr = ["£129.95", "£179.95","£169.95","£199.85"]
2. Convert input data in array of Int and Double
let quantities = quntityArr
.compactMap(Int.init)
let prices = priceArr
.map { $0.dropFirst() }
.compactMap (Double.init)
3. Verify no input value has been discarded
assert(quntityArr.count == quantities.count)
assert(priceArr.count == prices.count)
4. Do the math
let results = zip(quantities, prices).map { Double($0) * $1 }.map { "£\($0)"}
5. Result
["£129.95", "£539.8499999999999", "£679.8", "£1398.95"]
I have 2 arrays, both of kind [[String:Any]] , where each element :
["date":Date,"value":CGFloat] //always looks like this
I might even have more than 2 (!)
I would like to create a single array with the same structure that sums all of them (2 or more) for each date that appears in all of them.
If the date of array1 does not appear on the others(array2, etc) I will simply add 0 to the value at array 1 for this specific date.
Is there a simple efficient way to do so ?
Instead of dictionaries use structs, it's more convenient:
struct MyStruct {
let date: Date
let value: CGFloat
}
Let's create 3 arrays of MyStructs:
let now = Date()
let later = now.addingTimeInterval(3600)
let earlier = now.addingTimeInterval(-3600)
let array1: [MyStruct] = [MyStruct(date: now, value: 1),
MyStruct(date: later, value: 2)]
let array2: [MyStruct] = [MyStruct(date: now, value: 3),
MyStruct(date: later, value: 4)]
let array3: [MyStruct] = [ MyStruct(date: earlier, value: 5),
MyStruct(date: later, value: 6)]
Now, let's group the elements and add the values for the elements with the same date property:
let allArrays = array1 + array2 + array3
let dict = Dictionary(allArrays.map { ($0.date, $0.value) },
uniquingKeysWith: { $0 + $1 })
All you have to do now is convert it back to an array of MyStruct:
let newArray = dict.map { MyStruct(date: $0.key, value: $0.value) }
And you can check the results like so:
for element in newArray {
print("date =", element.date, "value =", element.value)
}
I found a way, assuming data is inside a structure(not a dic) which is a better practice.
I will put all arrays into a single large array, sort it by dates, loop on it and as long as date is equal previous date(or close enough to equality), I will sum the values up. When the next date is different, I will save the date and the sum.
//create a combined array from all given arrays
var combined = [RootData]()
for list in dataSets {combined.append(contentsOf: list)}
//sort it by dates
let sortedArray = combined.sorted { $0.date < $1.date }
//new array - sum of all
var sumData = [RootData]()
var last:Date = sortedArray[0].date //set starting point
var sum:CGFloat = 0
for element in sortedArray
{
//same date - accumulate(same is less than 1 sec difference)
if(abs(element.date.seconds(from: last)) <= 1) {
sum+=element.value
}
//save
else {
sumData.append(RootData(value:sum,date:last))
sum=element.value
}
last=element.date
}
//last object
sumData.append(RootData(value:sum,date:last))
return averageData
Here RootData is a simple structure for the data with :
value:CGFloat
date:Date
Works as expected.
Because dates are not always completely equal , I check equality by assuming 1 second or less is the same date.
I am trying to change my string value in an array after shuffling another array, how am i to do this?
Example:
var array1 = [1,2,3,4,5,6]
var stringarray = ["\\(array1[0]) = 1")
array1.shuffle()
print(stringarray)
How am i to change the original stringarray value to the new shuffled value?
Thank you
The task:
#IBAction func nextQuestion(_ sender: Any) {
if levelSelected == 1 {
questionLabel.text = standardRules.randomElement()
}
players.shuffle()
print(players)
standardRules has a string value that takes the value of players[0]
Essentially what i am trying to do is this:
I am trying to grab 2 random values that are not the same in a string like this
var players = ["Jack, John, Michael, Peter"]
var playersArray = ["\(players.randomElement) and \(players.randomElement) has to battle")
How am i to do this, so it grabs 2 different values?
You could make it very easy by this code :
var players = ["Jack", "John", "Michael", "Peter"]
// get the first random element
var random1 = players.randomElement()
//delete that element so you can't duplicate it
players = players.filter{$0 != random1}
//get your second radom element
var random2 = players.randomElement()
//add your element again
players.append(random1!)
Looks like you're missing some core concepts of the Swift language. When you create your stringarray it makes a call of array1.description and stores the result into an array. From that point any modifications of the original array will not change anything in stringarray.
So if you want to pick two different players from an array you need to do something like that:
let index1 = Int.random(in: (0 ..< players.count))
var index2: Int
repeat {
index2 = Int.random(in: (0 ..< players.count))
} while index1 == index2
let matchText = "\(players[index1]) and \(players[index2] has to battle)"
I would try replacing:
var stringarray = ["\\(array1[0]) = 1")
array1.shuffle()
with:
var stringarray = array1.shuffle()
I would to know how to get key if I have the values. Which class get higher marks?
let higherMarks = [
"ClassA": [10,20,30,40,50,60],
"ClassB": [15,25,35,45,55,65],
"ClassC": [18,28,38,48,58,68],
]
var largest = 0
var className = ""
for (classTypes, marks) in higherMarks {
for mark in marks {
if mark > largest {
largest = mark
}
}
}
print(largest)
What I'm saying in my comment is that you need to get the classTypes when you get the mark. Because when you get the higher mark, you want to also get the corresponding key value.
Keeping your code's logic I would do something like this:
let higherMarks = [
"ClassA": [10,20,30,40,50,60],
"ClassB": [15,25,35,45,55,65],
"ClassC": [18,28,38,48,58,68],
]
func findBestClass(in results: [String: [Int]]) -> (name: String, score: Int) {
var largest = 0
var type = ""
for (classType, marks) in results {
if let max = marks.max(), max > largest {
largest = max
type = classType
}
}
return (type, largest)
}
let best = findBestClass(in: higherMarks)
print("The best class is \(best.name) with a score of \(best.score).")
I just replaced your inner loop with .max() and changed the name of the key variable because it should not be plural. My method also returns a tuple because I find it relevant in this situation. But I didn't change your logic, so you can see what I meant by "also get the classTypes".
I have an array of Strings containing user inputted values. I have a string containing several words (the number of words in the string varies). I want to increment an Int every time one of the words in the string matches a word in the array.
I'm using this method:
var searchWordsArr: [String] = [] \\filled by user input
var message: String = "" \\random number of words
var numRelevantWords = 0
var i = 0
while i < self.searchWordsArr.count {
i+=1
if message.contains(self.searchWordsArr[i-1]) {
numRelevantWords += 1
}
}
In my first example, the string contained 25 words and the array contained 3 words. The 3 words came up a total of 12 times in the string. Using the above method, the value of numRelevantWords was 2.
I would use regex. Some day soon, Swift will have native regular expressions. But until it does, you have to resort to Foundation:
let words = ["the", "cat", "sat"]
let input = "The cat sat on the mat and the mat sat on the catastrophe"
var result = 0
let pattern = "\\b(" + words.joined(separator:"|") + ")\\b"
do {
let regex = try NSRegularExpression(pattern: pattern, options: .caseInsensitive)
let match = regex.matches(in: input, options: [], range: NSRange(location: 0, length: input.utf16.count))
result += match.count // 7, that's your answer
} catch {
print("illegal regex")
}
Add them to a NSCountedSet:
let searchWords = NSCountedSet()
searchWords.add("Bob")
searchWords.add("John")
searchWords.add("Bob")
print(searchWords.count(for: "Bob")) // 2
"pure" Swift (no Foundation)
let message = "aa bb aaaa ab ac aa aa"
let words = message.characters.split(separator: " ").map(String.init)
let search:Set = ["aa", "bb", "aa"]
let found = words.reduce(0) { (i, word) -> Int in
var i = i
i += search.contains(word) ? 1 : 0
return i
}
print(found, "word(s) from the message are in the search set")
prints
4 word(s) from the the message are in the search set
UPDATE (see discussion)
using Set
var search: Set<String> = [] // an empty set with Element == String
search.insert("aa") // insert word to set
using Array
var search: Array<String> = [] // an empty array
search.append("aa") // append word to array
maybe you are looking for
let message = "the cat in the hat"
let words = message.characters.split(separator: " ").map(String.init)
let search:Set = ["aa", "bb", "pppp", "the"]
let found = search.reduce(0) { (i, word) -> Int in
var i = i
i += words.contains(word) ? 1 : 0
return i
}
print(found, "word(s) from the search set found in the message")
prints
1 word(s) from the search set found in the message
if you would like to produce the same as with accepted answer
let words = ["the", "cat", "sat"]
let input = "The cat sat on the mat and the mat sat on the catastrophe"
let inputWords = input.lowercased().characters.split(separator: " ").map(String.init)
let found = inputWords.reduce(0) { (i, word) -> Int in
var i = i
i += words.contains(word.lowercased()) ? 1 : 0
return i
}
print(found, "word(s) from the search set found in the message")
prints
7 word(s) from the search set found in the message