I am very new to Swift and this problem has got me stumped. I am trying to create a two-dimensional map. In init of my Map class, I need to create a two-dimensional array of another class called Grid.
This is what I have right now:
class Map: NSObject {
var squares: [[Grid]]
let MAXROWS = 200
let MAXCOLUMNS = 200
override init(){
for r in 0...MAXROWS{
for c in 0...MAXCOLUMNS{
squares[r][c].append
}
}
}
At the append function, it creates an error:
value of type "Grid" has no member "append"
How do I do this correctly?
Or if you don't like raw loops:
override init(){
self.squares = Array<[Grid]>(
repeating: Array<Grid>(
repeating: Grid(),
count: MAXCOLUMNS),
count: MAXROWS
)
}
edit: Like Alain T metnioned, this only works if Grid is a struct, otherwise the same instance would be used throughout the 2d array. This is because classes are passed by reference, and in this case, the same reference would be used every single time.
You could also do it like this (because Grid is a class):
squares = (0..<MAXROWS).map{_ in (0..<MAXCOLUMNS).map{_ in Grid()}}
This uses the ranges as a means to "generate" the desired number of elements in the array. The map() function returns an entry for each generated number. Entries for rows are arrays of columns each containing a new instance of a Grid object. The "_ in" inside the map() closures tells the compiler that we are not actually using the value produced by the ranges.
try it:
class Map: NSObject {
var squares: [[Grid]]
let MAXROWS = 200
let MAXCOLUMNS = 200
override init(){
for r in 0...MAXROWS{
squares.append([])
for c in 0...MAXCOLUMNS{
squares[r].append(Grid())
}
}
}
Related
If you have a collection type in Swift (like a Set<T>) then you can remove something from the set like...
var s = // some set
s.remove(someElement)
and it will mutate s and remove the someElement from it.
However, this is a mutating function.
Is there a non-mutating function that would return a new set? Like...
let smallerSet = largerSet.removing(someElement)
I could use filter but then it turns this from a O(1) into an O(n) time problem.
If there isn't one already I can write one myself. Is there a convention for the name of a non-mutating function like this?
You can use subtracting function of the Set. For that you need to put that element to be deleted in another Set.
let elementToBeDeleted = Set(arrayLiteral: 1)
var wholeSet = Set(arrayLiteral: 1,2,3)
wholeSet = wholeSet.subtracting(element)
print(wholeSet) //This would print [2,3].
Hope this what you need to get things done.
This question has been asked and answered for a couple other coding languages, but I think I may have a unique problem anyway. So, I want to duplicate a three dimensional array (filled with arbitrary objects). I believe I found that this:
var duplicateArray = originalArray
Does not work, since, for whatever reason, they thought it would a nice safety measure to have this create a duplicate array, but filled with pointers as sub-arrays instead of duplicating the sub-arrays as well. This seems like a strange design choice, since if duplicateArray and originalArray were one-dimensional, this would work as intended. Anyway, so I tried this (where object is some arbitrary object):
var duplicateArray = [[[object]]]()
for x in 0..<originalArray.count {
var tempArrYZ = [[object]]()
for y in 0..<originalArray[x].count {
var tempArrZ = [object]()
for z in 0..<originalArray[x][y].count {
let copiedObj = originalArray[x][y][z]
tempArrZ.append(copiedObj)
}
tempArrYZ.append(tempArrZ)
}
duplicateArray.append(tempArrYZ)
}
This still does not work; all the values in duplicateArray will act like a pointer for their values in originalArray. Perhaps someone has a simple way of deeply duplicating multidimensional arrays, or perhaps someone can find my error?
EDIT: How is this a duplicate of that other question? I'm asking specifically how to "deeply" duplicate. The question that's being referred to nebulously asked about duplicating arrays.
var duplicateArray = originalArray
Would work if the objects are not of reference type. However, for the reference type you need to actually create the copy of the object with copy. Your original code was pretty close.
var duplicateArray = [[[object]]]()
for x in 0..<originalArray.count {
var tempArrYZ = [[object]]()
for y in 0..<originalArray[x].count {
var tempArrZ = [object]()
for z in 0..<originalArray[x][y].count {
let copiedObj = originalArray[x][y][z].copy()
tempArrZ.append(copiedObj)
}
tempArrYZ.append(tempArrZ)
}
duplicateArray.append(tempArrYZ)
}
As already stated, your problem isn't really the copying of the array, it's the copying of Objects. Arrays, like all structs, are copied by value. Objects are copied by reference.
When you copy an array of objects, it's a brand new array with brand new references to the contained objects. Your code is simply creating additional references to the same objects then organizing them in a similar fashion.
Anyway, here's my simpler/functional implementation for copying arrays:
func copyArrayWithObjects <T: Copying>(items: [T]) -> [T]{
return items.map { $0.copy() }
}
func copy2DArrayWithObjects <T: Copying>(items: [[T]]) -> [[T]] {
return items.map(copyObjectsInArray)
}
func copy3DArrayWithObjects<T: Copying>(items: [[[T]]]) -> [[[T]]] {
return items.map(copy2DObjectInArray)
}
Then you can simply do this:
let copiedArray = copy3DArrayWithObjects(originalArray)
Theoretically I think it's possible to create a function to do this for an n-dimension array, but I haven't found a solution yet.
I think it would be best to write an extension on Array that adds conformance to NSCopying, which recursively copies the elements. This solution would be very elegant because it could scale to any number of dimmensions.
Swift arrays are value types so the snippet you provided is fine.
var duplicateArray = originalArray
See this example in a Playground as proof:
var array = [[["test"]]]
var newarray = array
// print different memory addresses
print(unsafeAddressOf(array[0][0][0])) // 0x00007ff7a302a760
print(unsafeAddressOf(newarray[0][0][0])) // 0x00007ff7a33000e0
If you use NSArray or reference types inside the Swift array, then they will no longer copy implicitly and will be treated with the same address - this can also be proved in the Playground. You would need to call copy() explicitly on reference types.
I was surprised by the following playground I created after seeing some unexpected behavior in my code:
import Foundation
let bytes:[UInt8] = [20, 30, 40, 50, 60, 70]
var stream = bytes.generate()
func consumeTwo(var stream:IndexingGenerator<[UInt8]>) {
print(stream.next())
print(stream.next())
}
consumeTwo(stream) // This prints 20 and 30
print(stream.next()) // This prints 20!? I expected 40!
I had thought that marking the stream argument as var to the consumeTwo() function, the stream state/position would be shared/updated as it moved from function to function. But that appears to not be the case.
Does this mean I need to make that an inout? And pass with the ampersand? When does one use the var if that's the case?
More generally... what is the right/idiomatic way to create a stream over a byte array which can be passed from function to function (e.g. a decoder) and preserve the position of the stream as it is passed around?
+1 for archaic English in the question title. :)
When you use var in a function signature, you create a local copy of that value. It's the same as if you did this:
func consumeTwo(stream: IndexingGenerator<[UInt8]>) {
var localStream = stream
print(localStream.next())
print(localStream.next())
}
When the parameter is a reference type (i.e. a class), the duplicate "value" is a duplicate reference to the same object. But the thing you get from Array.generate() is a value type, so your local copy is a separate iterator with separate state.
Does this mean I need to make that an inout? And pass with the ampersand?
Yes — for your simple example, inout (and pass with &) is a simple and idiomatic way to do this:
func consumeTwo(inout stream:IndexingGenerator<[UInt8]>) {
print(stream.next())
print(stream.next())
}
consumeTwo(&stream) // This prints 20 and 30
print(stream.next()) // This prints 40
Remember: when you want to modify a value type inside a function and later see those modifications outside the function, use inout. And the & goes with it, so that it's clear both inside the function and at the call site that this behavior is happening.
When does one use the var if that's the case?
Use var for parameters only when you want to make a copy that's local to the function invocation. Admittedly, the use cases for this are few. Here's a contrived (and completely unnecessary) one:
func bananify(var strings: [String]) {
for i in 1.stride(to: strings.count, by: 2) {
strings[i] = "banana"
}
print(strings.joinWithSeparator(" "))
}
let words = ["foo", "bar", "bas", "zap", "asdf"]
bananify(words) // "foo banana bas banana asdf\n"
If you find this confusing, you're not the only one. For this reason, removing the ability to use var for parameters is a planned change for Swift 3.
More generally... what is the right/idiomatic way to create a stream over a byte array which can be passed from function to function (e.g. a decoder) and preserve the position of the stream as it is passed around?
As user3441734 notes, you can indeed create and use a reference-type iterator instead. Or you can write a reference type that holds and manages an iterator. For your hypothetical case of sharing a stream among several subsystems of a program, this is probably a good approach — representing a shared resource is one of the canonical cases for using reference types.
you wrote "It makes me wish that Generators were objects instead of structs."
there is no trouble define some generator as reference type ...
class G: AnyGenerator<Int> {
var i = 0
override func next() -> Int? {
return i++
}
}
let g = G()
func foo(gen: G)->Void {
print(gen.next())
print(gen.next())
}
foo(g)
print(g.next())
/*
Optional(0)
Optional(1)
Optional(2)
*/
I'd like to create a function that will iterate over an array (or collection or sequence). Then I will call that function with an array, and the reversed version of the array (but efficiently: without creating a new array to hold the reverse).
If I do this:
func doIteration(points: [CGPoint]) {
for p in points {
doSomethingWithPoint(p)
}
// I also need random access to points
doSomethingElseWithPoint(points[points.count-2]) // ignore obvious index error
}
And if I have this:
let points : [CGPoint] = whatever
I can do this just fine:
doIteration(points)
But then if I do this:
doIteration(points.reverse())
I get 'Cannot convert value of type 'ReverseRandomAccessCollection<[CGPoint]> to expected argument type [_]'
Now, I DON'T want to do this:
let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)
even though it will work, because that will (correct me if I'm wrong) create a new array, initializing it from the ReverseRandomAccessCollection returned by reverse().
So I guess I'd like to write my doIteration function to take some sort of sequence type, so I can pass in the result of reverse() directly, but ReverseRandomAccessCollection doesn't conform to anything at all. I think I'm missing something - what's the accepted pattern here?
If you change your parameter's type to a generic, you should get the functionality you need:
func doIteration
<C: CollectionType where C.Index: RandomAccessIndexType, C.Generator.Element == CGPoint>
(points: C) {
for p in points {
doSomethingWithPoint(p)
}
doSomethingElseWithPoint(points[points.endIndex - 2])
}
More importantly, this won't cause a copy of the array to be made. If you look at the type generated by the reverse() method:
let points: [CGPoint] = []
let reversed = points.reverse() // ReverseRandomAccessCollection<Array<__C.CGPoint>>
doIteration(reversed)
You'll see that it just creates a struct that references the original array, in reverse. (although it does have value-type semantics) And the original function can accept this new collection, because of the correct generic constraints.
You can do this
let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)
or this
doIteration(points.reverse() as [CGPoint])
but I don't think there is any real difference by the point of view of a the footprint.
Scenario 1
let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)
Infact in this case a new Array containing references to the CGPoint(s) present in the original array is created. This thanks to the Copy-on-write mechanism that Swift used to manage structures.
So the memory allocated is the following:
points.count * sizeOf(pointer)
Scenario 2
On the other hand you can write something like this
doIteration(points.reverse() as [CGPoint])
But are you really saving memory? Let's see.
A temporary variable is created, that variable is available inside the scope of the function doIteration and requires exactly a pointer for each element contained in points so again we have:
points.count * sizeOf(pointer)
So I think you can safely choose one of the 2 solutions.
Considerations
We should remember that Swift manages structures in a very smart way.
When I write
var word = "Hello"
var anotherWord = word
On the first line Swift create a Struct and fill it with the value "Hello".
On the second line Swift detect that there is no real reason to create a copy of the original String so writes inside the anotherWord a reference to the original value.
Only when word or anotherWord is modified Swift really create a copy of the original value.
I'm basically trying to do what this guy is trying to do, but with Swift:
Declaring a random amount of objects in c++
I'm pretty new to programming and very new to Swift so I'm a little fuzzy on how to do some things. Basically, I just want to declare a random amount of enemies that my player has to weave through and to register when he's hit one of them. I've been looking every where for an answer and either this is a really stupid question, so stupid no one has ever needed to put it on the internet, or Sift is too new for it to have been a problem for someone else. I'm guessing it's a stupid question, but regardless I'm out of ideas on how to figure this out.
Thanks.
Swift arrays are dynamic, at least the mutable type that are declared with var array.
So you can just add objects to your array until you have enough objects.
e.g.:
var objects = [String]()
//let numberOfObjects = arc4random_uniform(10) // between 0 and 9
let numberOfObjects = arc4random_uniform(5) + 5 // between 5 and 9
for i in 0..<numberOfObjects {
let object = String()
objects.append(object)
}
println("we have \(countElements(objects)) objects")
Maybe I'm too dense to understand the question, but it seems to me that simply declaring an NSMutableArray would do what you want:
let myArray:NSMutableArray = NSMutableArray()
You would have all the flexibility to add or remove objects as you please.
In any given loop, you could remove all objects, then use a random number generator to add back a random number of objects if that's what you're trying to do.
My additional comment on the other answer to this is that I would explicitly type cast everything in the statement that generates the random number:
var randomNumber:Int = Int(arc4random_uniform(UInt32(5)))
Here's an example using a simple Enemy class:
class Enemy : NSObject {
override init() {
super.init()
}
}
let range = (5, 20)
let numEnemies = Int(arc4random_uniform(UInt32(range.1 - range.0) + 1) + UInt32(range.0))
var enemyArray = [Enemy]()
for i in 0..<numEnemies {
enemyArray.append(Enemy())
}
You want a random number of objects in an array. Assume:
class MyObject {}
and that you have an upper bound on the number of objects:
let theObjectLimit = 10
then you can create a random number of new, distinct instances of MyObject with simply:
let theObjects = (1...arc4random_uniform(theObjectLimit)).map {
_ -> MyObject in return MyObject ()
}
When learning a language like Swift, that has first class functions (aka closures), you'll want to use functions like map and reduce wherever possible - especially instead of iteration.