I'm new to Swift and I am trying to create a array of arrays of a custom object. I did some research and what mostly came up online is:
Array(repeating: Array(repeating: [Object](), count: y), count: x)
or similar but I haven't been able to get them working for me. ( Deprecated because different swift versions,etc.. ) Right now I have
class ChessPiece {
// class definition...
}
class ChessBoard {
var board: [[ChessPiece]] = []
init() {
board = [[ChessPiece(),ChessPiece(),ChessPiece()],
[ChessPiece(),ChessPiece(),ChessPiece()],
[ChessPiece(),ChessPiece(),ChessPiece()]]
}
}
But what if I had 100 rows or columns? Isn't there a more efficient and direct way to create a matrix with x rows and y columns?
I just do with normal for-in loop
class ChessPiece {
// class definition...
}
class ChessBoard {
var board: [[ChessPiece]] = []
init(row: Int, column: Int) {
for _ in 1...row {
var innerArray: [ChessPiece] = []
for _ in 1...column {
innerArray.append(ChessPiece())
}
board.append(innerArray)
}
}
}
let chessBoard = ChessBoard(row: 8, column: 8)
The function you mentioned is fine Array(repeating:count:).
This works on my playground:
struct ChessPiece {}
func makeChessPlate(dimension: Int) -> [[ChessPiece]] {
return Array(repeating: Array(repeating: ChessPiece(), count: dimension), count: dimension)
}
print(makeChessPlate(dimension: 2)) // Result: [[ChessPiece, ChessPiece],[ChessPiece, ChessPiece]]
EDIT: Notice that my example works only because I used a struct instead of a class. On the contrary to classes, structs are copied by values, then this results in an array of unique objects.
You can use this loop to create a multidimensional array.
class ChessPiece{
}
var numColumns = 27
var numRows = 52
var array = [[ChessPiece]]()
for column in 0...numColumns {
array.append(Array(repeating: ChessPiece(), count:numRows))
}
This would create an array of array of ChessPieces.
Related
I want to write a program that can make random seats at my school in our diner.
I know this much
import Foundation
var randomNumbers: [Int] = []
for _ in 0...5 {
let randomInt = Int.random(in: 0...160)
randomNumbers.append(randomInt)
}
print(randomNumbers)
This prints 6 numbers between 1 and 160. I want to do this lets say 4 times. How would you make it so you can't sit together with people who you sat with before
I'd create an array of numbers 1-160 and randomize them with the shuffled method. When you want to a subset of the random numbers, grab the last six, then remove the last six from the array. That way you wan't get any duplicates.
class RandomNumberGenerator {
private var possible: [Int] = []
init(range: ClosedRange<Int>) {
reset(range: range)
}
func next(count: Int) -> [Int] {
let result = possible.suffix(count).map { $0 }
possible.removeLast(result.count)
return result
}
func reset(range: ClosedRange<Int>) {
possible = range.map { $0 }.shuffled()
}
private init() {}
}
let rando = RandomNumberGenerator(range: 1...160)
for _ in 0..<4 {
print(rando.next(count: 6))
}
Note that the array will run out of numbers if you call it more than 26 times. So to restore all the values in the array simply call reset:
rando.reset(range: 1...160)
I have 2 structs, first is:
struct LineData {
init (name: String,
colorValue: String,
values: [Int]){
self.name = name
self.colorValue = colorValue
self.values = values
}
private var cachedMaxValue: Int? = nil
let name: String
let colorValue: String
let values: [Int]
// describe max value for Y axis for specific Line
mutating func maxValue() -> Int{
if let cached = cachedMaxValue {
return cached
}
self.cachedMaxValue = values.max()
return cachedMaxValue ?? 0
}
}
Second have array of LineData structs:
struct CharData {
init(xAxis: XAxis,
lines: [LineData]){
self.xAxis = xAxis
self.lines = lines
}
private var cachedMaxValue: Int? = nil
var xAxis: XAxis
var lines: [LineData]
// describe max value for Y axis among lines
func maxValue() -> Int{
var maxValues: [Int] = []
lines.forEach{it in
maxValues.append(it.maxValue())
}
return 0
}
}
Code above not compile, because, of error on method maxValues for struct CharData. It says Cannot use mutating member on immutable value: 'it' is a 'let' constant
What i want is, iterate through an array of lines and among it max values find greater value.
Since lines is an ordinary array, how about simply:
for i in 0..<lines.count {
maxValues.append(lines[i].maxValue())
}
perhaps not quite as Swifty, but nothing gets copied. The optimizer ought to give you pretty much the same performance as forEach.
It's the it parameter/object in the forEach that's immutable. Just like the error says: "it is a let". You could probably do something like this:
lines.forEach { it in
var mutableIt = it
maxValues.append(mutableIt.maxValue())
}
It should be noted that this will create a mutable copy of the "it" struct instance.
I have the following code:
(0...engine.rows-1).forEach {row in
(0...engine.cols-1).forEach {col in
//print("(\(row),\(col)) state = \(engine.grid[(row,col)])")
switch engine.grid[(row,col)] {
case CellState.empty: emptyCount = emptyCount + 1
case CellState.alive: aliveCount = aliveCount + 1
case CellState.died: diedCount = diedCount + 1
case CellState.born: bornCount = bornCount + 1
}
}
}
It looks like filters could do this more efficiently but I don't understand the syntax for a complex object. If not filters is there a better way to do nested loops in swift?
Thanks
This looks like Conway's Game of Life.
You are looping through a grid counting the various cell states. Nested loops is the natural way to do this. I would suggest using for in instead of forEach. Also, I would suggest creating a dictionary to hold the counts:
// Create dictionary to hold counts
var counts: [CellState : Int] = [.alive: 0, .died: 0, .born: 0, .empty: 0]
for row in 0 ..< engine.rows {
for col in 0 ..< engine.cols {
//print("(\(row),\(col)) state = \(engine.grid[(row,col)])")
counts[engine.grid[(row, col)]] += 1
}
}
Another way:
You've given us no information on your Engine class or struct. Depending on the implementation of grid, there might be a way to get an array of all of the cells.
For instance, if you use N-Dimensional Array to create the grid, then you can get all of the cells as an array with grid.data.
struct Engine {
let rows: Int
let cols: Int
var grid: NDimArray<CellState>
init(rows: Int, cols: Int) {
self.rows = rows
self.cols = cols
self.grid = NDimArray<CellState>(dimensions: rows, cols, initial: CellState.empty)
}
}
Setting a cell state would look like:
var engine = Engine(rows: 20, cols: 20)
engine.grid[0, 0] = .alive
engine.grid[0, 1] = .alive
Then the code to count the cells types becomes:
var counts: [CellState : Int] = [.alive: 0, .died: 0, .born: 0, .empty: 0]
engine.grid.data.forEach { cell in counts[cell] += 1 }
I'm working on a project where I need to work with large arrays, and by using UnsafeMutablePointers, I get a threefold speed increase over using the regular array methods. However, I believe the copy on write behavior is causing me to change instances that I do not want to be affected. For example, in the following code, I want to update the values in copyArray, but leave the original values in anArray.
import Foundation
func increaseWithPointers(_ arr: inout [Int]) {
let count = arr.count
let ptr = UnsafeMutablePointer(mutating: &arr)
for i in 0..<count {
ptr[i] = ptr[i] + 1
}
}
var anArray = [1,2,3,4,5]
var copyArray = anArray
increaseWithPointers(©Array)
print(anArray)
Executing this code prints [2,3,4,5,6].
I can get around this by declaring copyArray as follows:
var copyArray = [Int](repeating: 0, count: 5)
for i in 0..<5 {
copyArray[i] = anArray[i]
}
However, this requires writing each value twice: to zero, then to the intended value. Is there a way to efficiently guarantee a copy of an array?
I can reproduce your problem using Xcode 9 beta 3, but not using Xcode 8.3.3. I suggest you file a Swift bug report.
This fixes the problem:
import Foundation
func increaseWithPointers(_ arr: inout [Int]) {
arr.withUnsafeMutableBufferPointer { (buffer) in
for i in buffer.indices {
buffer[i] += 1
}
}
}
var anArray = [1,2,3,4,5]
var copyArray = anArray
increaseWithPointers(©Array)
print(anArray)
i have some question about swift 2 random. I have an enum sub class of all cards example:
enum CardName : Int{
case Card2Heart = 0,
Card2Diamond,
Card2Club,
Card2Spade,
Card3Heart..... }
I want to select 10 random cards on the didMoveToView
To get a unique, random set of numbers you can do the following...
Using the Fisher-Yates shuffle from here... How do I shuffle an array in Swift?
You can do...
var numbers = Array(0...51)
numbers.shuffleInPlace()
let uniqueSelection = numbers[0..<10]
or...
let uniqueSelection = Array(0...51).shuffleInPlace()[0..<10]
This will create a random, unique selection of 10 numbers (cards) from the array of 52 cards that you start with.
You can then iterate this array to get the enums or create an array of all enums to start from etc... There are lots of ways to use this.
In Swift 4.2 (coming with Xcode 10) the task will become much easier:
enum CardName: CaseIterable {
case Card2Heart
case Card2Diamond
case Card2Club
case Card2Spade
case Card3Heart
// ...
}
let randomCard = CardName.allCases.randomElement()
print(randomCard)
let randomCards10 = CardName.allCases.shuffled().prefix(10)
print(randomCards10)
Note there is no need for the enum to inherit from Int.
Following your last comment, here's a little, simplified example with the constraint of having to keep your enum for making the cards.
We need to include the extensions linked by Fogmeister:
extension MutableCollectionType where Index == Int {
/// Shuffle the elements of `self` in-place.
mutating func shuffleInPlace() {
// empty and single-element collections don't shuffle
if count < 2 { return }
for i in 0..<count - 1 {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
extension CollectionType {
/// Return a copy of `self` with its elements shuffled
func shuffle() -> [Generator.Element] {
var list = Array(self)
list.shuffleInPlace()
return list
}
}
These extensions will allow us to shuffle an array of values.
Which array?
There's many ways, but the simplest option is probably to make an array of indices, which are simple integers (replace 52 with the actual number of cards in your enum):
Array(1...52) // [1, 2, 3, ... , 52]
We shuffle it:
Array(1...52).shuffle() // [33, 42, 7, ...]
Now we have an array of randomized indices. Let's make cards from this with your enum:
Array(0...51).shuffle().flatMap({ CardName(rawValue: $0) })
This is it, we have an array of cards in a random order:
let shuffledDeck = Array(0...51).shuffle().flatMap({ CardName(rawValue: $0) }) // [Card3Heart, Card2Diamond, ...]
and we can take cards from it:
func takeCardsFromDeck(number: Int) -> [CardName] {
if shuffledDeck.count > number {
let cards = Array(shuffledDeck[0..<number])
shuffledDeck.removeRange(0..<number)
return cards
}
return []
}
let tenRandomCards = takeCards(10)
Of course we need to remove from the deck the cards we've dealt, that way each card you draw is unique: we're using removeRange for that.
This example was kept simple on purpose: you still have to verify that there's enough cards in the deck before drawing, and lots of unsuspected other complexities. But it's so fun. ;)
If you want, you can search for additional inspiration in my implementation of these models and others (Deck, Dealer, Player, etc) in my PokerHands repository (MIT Licenced) on GitHub.
Swift 4.2
No need for these extensions anymore, we can use the .shuffle() and .shuffled() methods provided by Swift. Just remove the extensions, and rename the methods: the equivalent of our old "shuffleInPlace" is now .shuffle() and the equivalent of our old "shuffle" is now .shuffled().
Note: see Sulthan's answer for an even better solution using Swift 4.2.
Here is the shuffleInPlace() code that you are missing;
extension MutableCollectionType where Index == Int {
mutating func shuffleInPlace() {
if count < 2 { return }
for i in 0..<count - 1 {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
how to randomly spread enum values set
import Darwin // arc4random_uniform
enum E:Int {
case E1, E2, E3, E4, E5, E6, E7, E8, E9, E10
static var set:[E] { return (E.E1.rawValue...E.E10.rawValue).flatMap { E(rawValue: $0) }}
}
func spread(i:Int = 0, arr:[E])->([E],[E]) {
var i = i == 0 ? arr.count : i
var e:[E] = []
var arr = arr
while i > 0 && arr.count > 0 {
let idx = Int(arc4random_uniform(UInt32(arr.count-1)))
e.append(arr.removeAtIndex(idx))
i -= 1
}
return (e,arr)
}
let e1 = spread(3, arr: E.set)
let e2 = spread(2, arr: e1.1)
// ... spread the rest
let e3 = spread(arr: e2.1)
print(e1, e2, e3, separator:"\n")
/*
([E.E8, E.E6, E.E4], [E.E1, E.E2, E.E3, E.E5, E.E7, E.E9, E.E10])
([E.E1, E.E7], [E.E2, E.E3, E.E5, E.E9, E.E10])
([E.E5, E.E3, E.E2, E.E9, E.E10], [])
*/