Swift: Slice startIndex always 0 - ios

I ran afoul of Swift Slice, thinking that firstIndex should be the first index of the slice, in the domain of the source (not sure what else it's useful for). Evidently this is not the case:
let ary = map(1...100) { i in i }
let s:Slice<Int> = ary[10..<20]
s.startIndex // 0
ary[10..<20].startIndex // 0
(10..<20).startIndex // 10 (half-open interval generated from a range, presumably)
Does this seem like a bug? If it's always 0, it seems totally useless.

NOTE: The following applies to Swift 2 or earlier. The behavior has changed since Swift 2.
If you dig around in the auto-generated Swift header file (where it seems most of the documentation is at the moment), you'll find this describing Slice:
/// The `Array`-like type that represents a sub-sequence of any
/// `Array`, `ContiguousArray`, or other `Slice`.
Since Slice is Array-like, it does make sense that startIndex would be returning 0 since an Array's startIndex is always going to be 0. Further down, where it defines startIndex, you'll also see:
/// Always zero, which is the index of the first element when non-empty.
var startIndex: Int { get }
If you're looking for the first entry in the Slice, just use: s.first:
/// The first element, or `nil` if the array is empty
var first: T? { get }
If you need to find the index in the original Array that where the Slice starts, you can do something like this:
if let startValue = s.first {
let index = find(ary, startValue)
/* ... do something with index ... */
}

This is fixed in Swift 2. If you slice an array with a range of 2...5, the startIndex of the slice will be 2. Very cool.

Related

index(where:) method in swift is producing the wrong index

I have received an array index out of range error. I have two arrays cardsCurrentlyInPlay and currentCardsSelected. Every card that is in this game has a unique ID. I am attempting to find find the index of the card in cardsCurrentlyInPlay whose cardID matches the cardID of the card in currentCardsSelected. I am doing this by using the index(where:) method that takes a closure. My closure just checks if the IDs match, they obviously match because I am using the ! to unwrap them and the app does not crash there. It seems as though the index(where:) method is returning the wrong index. I have looked at this for hours and I do not understand whats going on.
Heres the code:
let indexOfFirstCard = cardsCurrentlyInPlay.index(where: ({($0?.cardID == currentCardsSelected[0].cardID)}))!
let indexOfSecondCard = cardsCurrentlyInPlay.index(where: ({($0?.cardID == currentCardsSelected[1].cardID)}))!
let indexOfThirdCard = cardsCurrentlyInPlay.index(where: ({($0?.cardID == currentCardsSelected[2].cardID)}))!
if deck.isEmpty && selectedCardsMakeASet() {
/* Remove the old cards */
cardsCurrentlyInPlay.remove(at: indexOfFirstCard)
cardsCurrentlyInPlay.remove(at: indexOfSecondCard)
cardsCurrentlyInPlay.remove(at: indexOfThirdCard) // where code is blowing up
currentCardsSelected.removeAll()
/* Return indicies of cards to clear from the UI */
return .deckIsEmpty(indexOfFirstCard, indexOfSecondCard, indexOfThirdCard)
}
The index you’re getting is correct when your get it, but it becomes wrong when you remove other cards. Consider:
var a = ["x", "y", "z"]
let indexOfX = a.index(of: "x")! // returns 0
let indexOfZ = a.index(of: "z")! // returns 2
a.remove(at: indexOfX) // removes "x"; now a = ["y", "z"]
a.remove(at: indexOfZ) // index 2 is now out of bounds
You could interleave the calls to index(of:) and remove(at:), but a better approach would be to remove all three cards in a single pass, something like this:
let selectedCardIDs = currentCardsSelected.map { $0.cardID }
cardsCurrentlyInPlay = cardsCurrentlyInPlay.filter { card in
!selectedCardIDs.contains(card.cardID)
}
Note that this has the added benefit of avoiding the force unwrap, a sign of sounder logic.
This is because of out of bounds.
After the first two code excuted.
cardsCurrentlyInPlay.remove(at: indexOfFirstCard) &
cardsCurrentlyInPlay.remove(at: indexOfSecondCard)
there is only one element in the cardsCurrentlyInPlay .
Then if you excute cardsCurrentlyInPlay.remove(at: indexOfThirdCard), the program will crash.

"Preloading" A Dictionary With Keys in Swift

This is a fairly simple issue, but one I would like to solve, as it MAY help with performance.
I want to find out if Swift has a way to create a Dictionary, specifying ONLY keys, and maybe no values, or a single value that is set in each entry.
In other words, I want to create a Dictionary object, and "preload" its keys. Since this is Swift, the values could be 0 or nil (or whatever is a default empty).
The reason for this, is so that I can avoid two loops, where I go through once, filling a Dictionary with keys and empty values, and a second one, where I then set those values (There's a practical reason for wanting this, which is a bit out of the scope of this question).
Here's sort of what I'm thinking:
func gimme_a_new_dictionary(_ inKeyArray:[Int]) -> [Int:Int] {
var ret:[Int:Int] = [:]
for key in inKeyArray {
ret[key] = 0
}
return ret
}
let test1 = gimme_a_new_dictionary([4,6,1,3,0,1000])
But I'm wondering if there's a quicker way to do the same thing (as in "language construct" way -I could probably figure out a faster way to do this in a function).
UPDATE: The first solution ALMOST works. It works fine in Mac/iOS. However, the Linux version of Swift 3 doesn't seem to have the uniqueKeysWithValues initializer, which is annoying.
func gimme_a_new_dictionary(_ inKeyArray:[Int]) -> [Int:Int] {
return Dictionary<Int,Int>(uniqueKeysWithValues: inKeyArray.map {($0, 0)})
}
let test1 = gimme_a_new_dictionary([4,6,1,3,0,1000])
For Swift 4, you can use the dictionary constructor that takes a sequence and use map to create the sequence of tuples from your array of keys:
let dict = Dictionary(uniqueKeysWithValues: [4,6,1,3,0,1000].map {($0, 0)})
I presume you could optimize your code in terms of allocation by specifying the minimum capacity during the initialization. However, one liner may be the above answer, it's essentially allocation and looping to add 0 in each position.
func gimme_a_new_dictionary(_ inKeyArray:[Int], minCapacity: Int) -> [Int:Int] {
var ret = Dictionray<Int, Int>(minimumCapacity: minCapacity)
for key in inKeyArray {
ret[key] = 0
}
return ret
}
let test1 = gimme_a_new_dictionary([4,6,1,3,0,1000])
Take a look at this official documentation:
/// Use this initializer to avoid intermediate reallocations when you know
/// how many key-value pairs you are adding to a dictionary. The actual
/// capacity of the created dictionary is the smallest power of 2 that
/// is greater than or equal to `minimumCapacity`.
///
/// - Parameter minimumCapacity: The minimum number of key-value pairs to
/// allocate buffer for in the new dictionary.
public init(minimumCapacity: Int)

How to remove an element of a given custom type value from an array in Swift

I want to remove element of custom type value from an array.
I want to pass a variant instance to function to remove it from array, I don't want to use removeAtIndex().
var favoriteVariants: [Variant]
func removeVariant(variant: Variant)
{
}
If Variant is Equatable and you only want to remove the first one that matches:
if let idx = favoriteVariants.indexOf(variant) {
favoriteVariants.removeAtIndex(idx)
}
If it isn’t Equatable and you have some other matching criteria to find just one to remove:
let idx = favoriteVariants.indexOf {
// match $0 to variant
}
if let idx = idx {
favoriteVariants.removeAtIndex(idx)
}
(these are assuming Swift 2.0 – if 1.2, it’s find(favoriteVariants, variant) instead of indexOf, and there isn’t a version that takes a closure, though it’s not too hard to write one)
If there are multiple ones you want to remove in one go:
favoriteVariants = favoriteVariants.filter {
// criteria to _keep_ any given favorite
}
All of these could be wrapped in extensions if what you want to do is general enough to justify it.

In Swift, how do I set every element inside an array to nil?

var roomsLiveStates = [Firebase?]()
for ref in roomsLiveStates {
if ref != nil {
ref = nil
}
}
}
This doesn't seem to work.
You can just set each to nil:
for index in 0 ..< roomsLiveStates.count {
roomsLiveStates[index] = nil
}
As The Swift Programming Language says in its Control Flow discussion of for syntax:
This example prints the first few entries in the five-times-table:
for index in 1...5 {
println("\(index) times 5 is \(index * 5)")
}
... In the example above, index is a constant whose value is automatically set at the start of each iteration of the loop. As such, it does not have to be declared before it is used. It is implicitly declared simply by its inclusion in the loop declaration, without the need for a let declaration keyword.
As this says, the index is a constant. As such, you can not change its value.
You can also use a map:
roomsLiveStates = roomsLiveStates.map { _ in nil }
This is less code and a good habit to get into for other cases where you may want to create a processed copy of an array without mutating the original.
if you want to set each element in array to a numberic value(int, float, double ...), you can try vDSP framework.
Please check this:
https://developer.apple.com/documentation/accelerate/vdsp/vector_clear_and_fill_functions
You can also just reassign the whole array to one that only contains nil like:
roomsLiveStates = [Firebase?](count: roomsLiveStates.count, repeatedValue: nil)
Although now that I think about it, this doesn't seem so good, because (probably?) new memory gets allocated which is not fast at all
EDIT: I just checked and found that using .map is a lot slower in Debug builds. However on Release builds, .map is about 20% faster. So I suggest using the .map version (which also is quiet a bit prettier ;)):
array = array.map { _ in nil }
Iterating the array to map it, will result in poor performance (iteration + new allocation).
Allocating the array all over (init(repeating...) is better, but still allocates a new array, very costly.
The best way would be to zero out the data without allocating it again, and as every C programmer knows, that's why we have bzero and memset for.
It won't matter much for small arrays in a non repeating action, and as long as you remember it - using the smallest code possible could make sense, so sometimes using map or init makes sense.
Final note on the test - map and init use multiple allocations of the same size in this test, which makes allocation allot faster than in real world usage.
In general, memory allocation is not your friend, it is a time consuming process that may result in having to defragment the heap, calling kernel code to allocate new virtual memory, and also must use locks and/or memory barriers.
import Foundation
guard CommandLine.argc == 2, let size = Int(CommandLine.arguments[1]),size > 0 else {
fatalError("Usage: \(CommandLine.arguments[0]) {size}\nWhere size > 0")
}
var vector = [Int].init(repeating: 2, count: size)
let ITERATIONS = 1000
var start:Date
var end:Date
start = Date()
for _ in 0..<ITERATIONS {
vector = vector.map({ _ in return 0 })
}
end = Date()
print("Map test: \(end.timeIntervalSince(start)) seconds")
start = Date()
for _ in 0..<ITERATIONS {
vector = [Int].init(repeating: 0, count: size)
}
end = Date()
print("init(repeating:,count:) test: \(end.timeIntervalSince(start)) seconds")
start = Date()
for _ in 0..<ITERATIONS {
let size = MemoryLayout.size(ofValue: vector[0]) * vector.count // could optimize by moving out the loop, but that would miss the purpose
vector.withUnsafeMutableBytes { ptr in
let ptr = ptr.baseAddress
bzero(ptr, size)
}
}
end = Date()
print("bzero test: \(end.timeIntervalSince(start)) seconds")
Results when running with an array of 5,000,000 items size (M1 Mac), compiled with optimizations:
Map test: 5.986680030822754 seconds
init(repeating:,count:) test: 2.291425108909607 seconds
bzero test: 0.6462910175323486 seconds
Edit:
Just realized it's also to initialize the memory using the initializeMemory(...) method.
Something like:
_ = vector.withUnsafeMutableBytes { ptr in
ptr.initializeMemory(as: Int.self, repeating: 0)
}
The performance is virtually the same as with bzero, and it is pure swift and shorter.

Swift playground execution speed

Is there a way to increase execution speed of a playground?
I want to iterate many cycles and not to wait 10 minutes.
For example:
import UIKit
var count = 0
for var i = 0; i < 1000000000; i++ {
count++
}
This code will execute a way too long. But I want to get quick result.
One of the biggest performance killer is the output at the right side of the playground. Now I will show you how to minimize this output.
See at the end for your example code.
Best Performance
The most performant way is to make all the performance critical code in a .swift file inside the Sources folder in the playground.
Note: In order to use the functions, classes, properties and methods from the Sources folder you have to mark them public. If you want to subclass a class it has to be marked open.
Good Performance but ugly code
The following method (I think this is not official/intended) can be used to disable the playground output but also leads to ugly code. However it is good for temporary disabling the output.
There are two main ways (and two tricks) to achieve the minimum amount of output (If you find a better way let us know):
Use parenthesis around Void (or Void?) expressions like assignments (normally leads to no output, see also 3.).
var x = 0 // output: 0
(x = 1) // NO output
(x = 2 * x - 1) // NO output
(x.negate()) // NO output
Note: In Swift an assignment returns Void and in case of optional chaining it is Void?.
var x: (Int, Int)? = nil
if (x?.0 = 0) != nil {
// assignment was successful (x!=0 and now x=(0, x.1))
} else {
// assignment was not successful (x==nil)
}
Initialize and declare variables separately.
var x: Int // NO output
(x = 0) // NO output
If 1. does not work add an additional no-op (no operation) line above or below ().
This happens in single line closures (and probably in some other contexts) for example: (see also the code below)
[1, 4, 5, 6].mmap{
() // without this line the line below would yield to an output
($1 = $0 + 1)
} as [Int]
Instead of wrapping every line in parenthesis you can also use a tuple of all the expressions which is then assigned to a variable:
var a: Any // this may be a useful definition in this context
var x: Int
var y: Int
(a = (x = 0,
y = 1,
x = y + 1,
y = x*x))
However this could lead to a indentation disaster...
Where it does not work (I've found no way how to remove the output; This list is probably not complete):
returns in functions and closures
Declaration of Optional variables e.g.: var x: Int?
An example of a new map method on Sequence
Usage: See above at Point 3.
The signature of Sequence.map is
func map<T>(_ transform: (Self.Element) throws -> T) rethrows -> [T]
Since I have not found a way how to remove the output of returns one can use a closure with an inout argument (get the "return" value with an assignment). A possible signature could then be:
func mmap<U>(_ transform: (Element, inout U?) -> ()) -> [U]
so we can pass nil in the inout argument since it is a good default for every possible U without imposing a constraint on U which could require an instance generator (e.g.: init() { ... }).
Unfortunately Swfit has a hard time to infer U so you would need to help the compiler with explicit type annotations. In addition var newElement: U? does return nil in the sidebar.
Now I will use Any instead of U?:
extension Sequence {
// ATTENTION: this is not as performant as the normal `map`!
func mmap<U>(transform: (Element, inout Any) -> ()) -> [U] {
var result: [U]
(result = [U]())
for element in self {
var newElement: Any
(newElement = 0) // some placeholder element
(transform(element, &newElement))
// assume the inout element to be of type `U`
(result.append(newElement as! U))
}
return result // the ONLY output in this method
}
}
Your example code
Using Swift 4
var count = 0
for i in 0..<1_000_000_000 {
(count += 1)
if count % 100_000 == 0 {
// print only every 100_000th loop iteration
print(count)
}
}
Without the parenthesis: about 10.000 loop iterations per second
With parenthesis: about 10.000.000 loop iterations per second !!!
I feel your pain, I was playing around with printing 2D functions to [Double] then converting to UIImageView. One of the steps was iterating over millions of pixels, and it took forever.
Anything computationally intensive, or repetitive, or potentially time consuming should be put in the "Sources" folder of the playground. That way the code is precompiled before your playground is run. Put the output of that for loop in a public function that you can call from the playground. Then you won't have to sit there watching the playground count all the times it went through the for loop.
I had a such problem and I have solved it after days of trials. All I needed to do is move all my code in folder Sources of playground. So, after that the execution speed was enhanced.
I hope it helps you.
Note: don't forget to use open classes.
To speed up the build in Xcode Playground and prevent the loading icon to keep spinning forever:
go to the sidebar on the right, and change iOS to macOS in Playground Settings
instead of importing UIKit, import Foundation
(this would work if you're not trying to use specific stuff from the UIKit framework)

Resources