I want to increase each key and value in this dictionary by 0.5
var times = [0800.0:0855.0,0900.0:0939.0,0942.0:1021.0,1023.0:1054.0,1057.0:1136.0]
I'd recommend you to formulate a more elaborated question the next time.
What did you tried?. Where did you get stuck?.
A good startpoint is this guide.
Having said that, and asking what I think was your question:
The naive way of doing it is by iterating over the values and keys, increment the value/key and then remove the previous key:
for (k, v) in times {
times[k + 0.5] = v + 0.5
times[k] = nil
}
The problem with this approach is that if k + 0.5 exists in the dictionary at any point, the value will be overwritten.
Option B
var newTimes = [Double: Double]()
for (k, v) in times {
newTimes[k + 0.5] = v + 0.5
}
times = newTimes
If I understood your request better than how you put it, you are using the wrong data structure. You have a list of time ranges, not values of time associated to other values of time.
So, my suggestion is that first of all, instead of [Double: Double] you use a [ClosedInterval<Double>]. It's also cooler to define it, like let times = [0800.0 ... 0855.0, 0900.0 ... 0939.0].
Then, from there, it's quite easy to do what you requested:
let shiftedTimes = times.map { ($0.start + 0.5) ... ($0.end + 0.5) }
n.b.: The thing here is, always find the most suited data structure to the data. And most suited isn't the one I know better, but the one that represents it better.
EDIT
By improving on the solution, I'd say that the preferred type would be [ClosedInterval<NSTimeInterval>], that you can define operators like this:
func +<T: IntegerArithmeticType>(lhs: ClosedInterval<T>, rhs: T) -> ClosedInterval<T> {
return (lhs.start + rhs) ... (lhs.end + rhs)
}
func +<S: Strideable, T where S.Stride == T>(lhs: ClosedInterval<S>, rhs: T) -> ClosedInterval<S> {
return (lhs.start + rhs) ... (lhs.end + rhs)
}
and then the whole operation becomes let shiftedTimes = times.map { $0 + 0.5 } :)
Related
I am new in Swift.
I have an error with this code and I can't find any answer on this site.
I print largest number but I want to print largest number's kind.
let interestingNumbers = [
"Prime": [2,3,5,7,11,13],
"Fibonacci": [1,1,2,3,5,8,13],
"Square": [1,4,9,16,25,36]
]
var largestNumber = 0
for (kind, numbers) in interestingNumbers {
for x in numbers {
for y in kind {
if x > largestNumber {
largestNumber = x
}
}
}
}
print("the largest number is = \(largestNumber)")
Try this instead:
var largestNumber = 0
var largestNumberKind: String!
for (kind, numbers) in interestingNumbers {
for x in numbers {
if x > largestNumber {
largestNumber = x
largertNumberKind = kind
}
}
}
print("the largest number is = \(largestNumber)")
print("the largest number kind is = \(largestNumberKind)")
Regarding your original code:
you were only keeping track of the largest number, losing the kind info you wanted. The largestNumberKind variable I added does just that.
looping over the kind: String didn't make any sense (the for y in kind line). Your outside loop already iterates a key at a time, so such inner loop is pointless.
There is nothing wrong with Paulo's approach (with some minor corrections; see comments there), but this is a reasonable problem to explore more functional approaches that don't require looping and mutation.
For example, we can just flatten each kind to its maximum element (or Int.min if it's empty), then take the kind with the highest max:
interestingNumbers
.map { (kind: $0, maxValue: $1.max() ?? .min) } // Map each kind to its max value
.max { $0.maxValue < $1.maxValue }? // Find the kind with the max value
.kind // Return the kind
This does create a slight edge condition that I don't love. If you evaluate the following:
let interestingNumbers = [
"ImaginaryReals": [],
"Smallest": [Int.min],
]
It's not well defined here which will be returned. Clearly the correct answer is "Smallest," but it's kind of order-dependent. With a little more thought (and code) we can fix this. The problem is that we are taking a little shortcut by treating an empty list as having an Int.min maximum (this also prevents our system from working for things like Float, so that's sad). So let's fix that. Let's be precise. The max of an empty list is nil. We want to drop those elements.
We can use a modified version of mapValues (which is coming in Swift 4 I believe). We'll make flatMapValues:
extension Dictionary {
func flatMapValues<T>(_ transform: (Value) throws -> T?) rethrows -> [Key: T] {
var result: [Key: T] = [:]
for (key, value) in self {
if let newValue = try transform(value) {
result[key] = newValue
}
}
return result
}
}
And with that, we can be totally precise, even with empty lists in the mix:
interestingNumbers
.flatMapValues { $0.max() }
.max { $0.1 < $1.1 }?
.key
Again, nothing wrong with Paulo's approach if you find it clear, but there are other ways of thinking about the problem.
BTW, the equivalent version that iterates would look like this:
var largestNumber: Int? = nil
var largestNumberKind: String? = nil
for (kind, numbers) in interestingNumbers {
for x in numbers {
if largestNumber == nil || largestNumber! < x {
largestNumber = x
largestNumberKind = kind
}
}
}
I'd like to test if a number (n) or more elements of a Sequence or Collection will return true when passed to a function. I'm not interested in how many elements would return true, just if n or more would or would not. I can get the correct result with this code:
let result = collection.filter { test($0) }.count > (n-1)
But the test function is called once for each element of collection. Is there a better (or possibly 'lazy') way to do this?
I can do this manually but iterating over the collection something like:
let result:Bool = {
var nCount = 0
for object in collection {
if test(object) {
nCount = nCount + 1
if nCount >= n {
return true
}
}
}
return false
}()
But the first way seems a lot more elegant.
I understand that, in a worst-case scenario, every element would have to be tested. I'm just like to avoid the unnecessary computation if possible.
In the case n=1 (check if at least one element of the sequence passes
the test) you can use contains(where:) with a predicate:
let result = sequence.contains(where: { test($0) } )
or just
let result = sequence.contains(where: test)
In the general case (check if the sequence contains at least a given number of matching items) you can use a lazy filter. Example:
func isEven(_ i : Int) -> Bool { return i % 2 == 0 }
let numbers = Array(1...10)
let atLeast4EvenNumbers = !numbers.lazy.filter(isEven).dropFirst(3).isEmpty
print(atLeast4EvenNumbers)
If you add a print statement to the isEven function then you'll see
that it is not called more often than necessary.
I built this code sample in Swift Playgrounds as a proof-of-concept for part of a larger project that I'm working on. What I need to do is pass in a series of options (represented by optionsArray or testArray) where each int is the number of options available. These options will eventually be built into 300+ million separate PDFs and HTML files. The code currently works, and puts out the giant list of possibilities that I want it to.
My question is this: Is there a better approach to handling this kind of situation? Is there something more elegant or efficient? This is not something that will be run live on an app or anything, it will run from a command line and take all the time it needs, but if there is a better approach for performance or stability I'm all ears.
Things I already know: It can't handle a value of 0 coming out of the array. The array is a constant, so it won't happen by accident. The way the code down the line will handle things, 0 is a nonsensical value to use. Each element represents the number of options available, so 2 is essentially a Boolean, 1 would be false only. So if I needed placeholder elements for future expansion, they would be a value of 1 and show up as a 0 in the output.
Also, the final product will not just barf text to the console as output, it will write a file in the permutationEnding() function based on the currentOptions array.
let optionsArray: [Int] = [7,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,2,2,2,2,2,2,2,2]
let testArray: [Int] = [7,2,3,2]
var currentOptions: [Int] = []
var outputString: String = ""
func buildPermutations(array: Array<Int>) {
currentOptions.removeAll()
permutationRecursion(array: array, index: 0)
}
func permutationRecursion(array: Array<Int>, index: Int) {
for i in 1 ... array[index] {
currentOptions.append(Int(i-1))
if array.count > (index + 1) {
permutationRecursion(array: array, index: index + 1)
} else {
permutationEnding()
}
currentOptions.removeLast()
}
}
func permutationEnding() {
for i in 1 ... currentOptions.count { // Output Elements
outputString += String(currentOptions[i-1])
}
outputString += "\n" // Goes after output elements closing bracket.
}
// buildPermutations(array: optionsArray)
buildPermutations(array: testArray)
print(outputString)
Thoughts?
I think I've figured out what you're trying to do. You want a string output of every possible integer combination that could map all possible routes on the decision tree.
I got it down to four or five lines.
let n = testArray.count // for readability
let products = ([Int](1...n)).map({testArray[$0..<n].reduce(1, *)})
// products is the cross product of element i + 1 to element n of the array for all i in the array
let zipped = zip(testArray, products)
for i in 0..<testArray.reduce(1, *) { // this reduce is the cross product of the whole array
let treePath = zipped.map(){ String(i / $0.1 % $0.0) }.joined()
outputString += treePath + "\n"
}
One more edit: I think this might be faster with some fancy matrix operations like NumPy. I wonder if the Accelerate framework could do some magic for you, but I have not worked with it.
edit: I was curious so I timed it with this test array
let testArray: [Int] = [7,2,2,2,2,2,2,3,2]
The recursive function in the question was: 132.56 s
The zip-map here was: 14.44 s
And it appears to be exponential as I add elements to the test array.
I am using the vDSP_meanD function to determine the average of a data set (consecutive diferences from an array)
The code I am using is below
func F(dataAllFrames:[Double],std:Double,medida:String)->Double{
let nframes=dataAllFrames.count
var diferencas_consecutivas_media = [Double](count: dataAllFrames.count-1, repeatedValue:0.0)
var mediaDifConseq:Double = 0
for(var i:Int=1; i<dataAllFrames.count; i++){
diferencas_consecutivas_media[i-1]=dataAllFrames[i]-dataAllFrames[i-1]
}
var meanConseqDif = [Double](count: 1, repeatedValue:0.0)
var meanConseqDifPtr = UnsafeMutablePointer<Double>(meanConseqDif)
vDSP_meanvD(diferencas_consecutivas_media,1,meanConseqDifPtr,UInt(nframes))
print( meanConseqDif[0])
}
The function F is called within a thread block
let group = dispatch_group_create()
let queue = dispatch_queue_create("myqueue.data.processor", DISPATCH_QUEUE_CONCURRENT)
dispatch_group_async(group, queue) {
F(measureData,std: std, medida: medida)
}
The F function is called in multiple dispatch block with different variables instances every now and then i get different values for the value returned from vDSP_meanD is there any context where this may happen ?
May the thread call have some influence on that?
Any "lights" would be greatly appreciated
I wouldn't expect this code to work. This shouldn't be correct:
var meanConseqDif = [Double](count: 1, repeatedValue:0.0)
var meanConseqDifPtr = UnsafeMutablePointer<Double>(meanConseqDif)
vDSP_meanvD(diferencas_consecutivas_media,1,meanConseqDifPtr,UInt(nframes))
I believe this is pointing directly at the Array struct, so you're probably blowing away the metadata rather than updating the value you meant. But I would expect that you don't get the right answers at all in that case. Have you validated that your results are correct usually?
I think the code you mean is like this:
func F(dataAllFrames: [Double], std: Double, medida: String) -> Double {
let nframes = UInt(dataAllFrames.count)
var diferencas_consecutivas_media = [Double](count: dataAllFrames.count-1, repeatedValue:0.0)
for(var i = 1; i < dataAllFrames.count; i += 1) {
diferencas_consecutivas_media[i-1] = dataAllFrames[i] - dataAllFrames[i-1]
}
var mediaDifConseq = 0.0
vDSP_meanvD(diferencas_consecutivas_media, 1, &mediaDifConseq, nframes)
return mediaDifConseq
}
You don't need an output array to collect a single result. You can just use a Double directly, and use & to take an unsafe pointer to it.
Unrelated point, but you can get rid of all of the difference-generating code with a single zip and map:
let diferencasConsecutivasMedia = zip(dataAllFrames, dataAllFrames.dropFirst())
.map { $1 - $0 }
I haven't profiled these two approaches, though. It's possible that your approach is faster. I find the zip and map much clearer and less error-prone, but others may feel differently.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I recentrly started to work with swift, and me and my Mate are trying to make a Small game to test what we learned..
we made a sort of monster fighting game ,no moving object just clicking on the monster.
So far so good evrything works as it should, got Upgrade to get more Hp or Str to do more damage on the monster, and to get more Hp when it hits back.
that said. i'm made items to the game but i want them to drop by the monster.
made different types and would like to know if anyone knows a code to get a Drop Chance on the Items...
like
"Normal" = 73%
"Rare" = 25%
"Legend" = 2%
I Looked around on evry search engine but can't find anything that i need.
Hope to get a reply soon
Thanks.
Greetz Kristof.V
This logic is the same of the answer by Avt, just a different implementation.
let random = Int(arc4random_uniform(100))
switch random {
case 0...72: print("Normal")
case 73...97: print("Rare")
case 98...99: print("Legend")
default: fatalError("Wrong number")
}
Use a random function arc4random_uniform
Returns a random number between 0 and the inserted parameter minus 1.
For example arc4random_uniform(3) may return 0, 1 or 2 but not 3.
You can use it like:
let random = Int(arc4random_uniform(100))
if random < 73 {
// drop normal
}
else if random < 73+25 {
// drop rare
} else {
// drop legend
}
(Edited: to include also weapon type as per follow-up question Random number to print array (Swift))
As above, use the arc4random function. A more complete "Monster" example follows.
It could be appropriate to hold different rarity and weapon types as enum cases
enum Rarities {
case Normal
case Rare
case Legendary
}
enum Weapons {
case Knife
case Sword
case Katana
}
Each monster could be an instance of a Monster class with it's own specific item and rarity drop rates, initialized when creating the Monster object.
class Monster {
var name : String
var dropRatesRarity = [Rarities:Double]()
var dropRatesWeapons = [Weapons:Double]()
init(name: String, dropRatesRarity: [Rarities:Double], dropRatesWeapons: [Weapons:Double]) {
self.name = name
var rateSum = dropRatesRarity.values.reduce(0.0, combine: +)
var dropRatesCumSum = 0.0
for (k, v) in dropRatesRarity {
self.dropRatesRarity[k] = v/rateSum + dropRatesCumSum
dropRatesCumSum += v/rateSum
}
rateSum = dropRatesWeapons.values.reduce(0.0, combine: +)
dropRatesCumSum = 0.0
for (k, v) in dropRatesWeapons {
self.dropRatesWeapons[k] = v/rateSum + dropRatesCumSum
dropRatesCumSum += v/rateSum
}
}
func dropItem() -> (Weapons,Rarities) {
return (generateItemType(), generateRarity())
}
func generateRarity() -> Rarities {
let random = Double(Float(arc4random()) / Float(UINT32_MAX))
return dropRatesRarity.filter({ (k, v) in v >= random }).minElement({ $0.1 < $1.1 })?.0 ?? .Normal
}
func generateItemType() -> Weapons {
let random = Double(Float(arc4random()) / Float(UINT32_MAX))
return dropRatesWeapons.filter({ (k, v) in v >= random }).minElement({ $0.1 < $1.1 })?.0 ?? .Knife
}
}
Example for some Monster instance:
/* Example */
var myDropRatesRarity = [Rarities:Double]()
myDropRatesRarity[.Normal] = 73 // relative drop rates, needn't sum to 100
myDropRatesRarity[.Rare] = 25
myDropRatesRarity[.Legendary] = 2
var myDropRatesWeapons = [Weapons:Double]()
myDropRatesWeapons[.Knife] = 50
myDropRatesWeapons[.Sword] = 30
myDropRatesWeapons[.Katana] = 20
var myMonster = Monster(name: "Godzilla", dropRatesRarity: myDropRatesRarity, dropRatesWeapons: myDropRatesWeapons)
var myItem = myMonster.dropItem()
print(myMonster.name + " dropped a \(myItem.0) of \(myItem.1) rarity!")
/* "Godzilla dropped a Katana of Normal rarity!" */
/* ... most likely Normal rarity ... keep grinding! */