How to initialize an array using `repeating:count:` with distinct objects? [duplicate] - swift

This question already has answers here:
Swift: Creating an Array with a Default Value of distinct object instances
(2 answers)
Closed 6 years ago.
Surprisingly, the code below prints SAME while the initializer should call the Z() constructor each time. How can I initialize the array using this method with distinct instances of Z?
import Foundation
class Z {
var i: Int = 0
}
var z: [Z] = [Z](repeating: Z(), count: 10)
if z[0] === z[1] {
print("SAME")
} else {
print("NOT SAME")
}

I made an extension just for this!
extension Array {
/// Create a new Array whose values are generated by the given closure.
/// - Parameters:
/// - count: The number of elements to generate
/// - elementGenerator: The closure that generates the elements.
/// The index into which the element will be
/// inserted is passed into the closure.
public init(generating elementGenerator: (Int) -> Element, count: Int) {
self = (0..<count).map(elementGenerator)
}
}
class Z {
var i: Int = 0
}
let z = Array(generating: { _ in Z() }, count: 10)
print(z)

Related

Form an array of Integers from integer value [duplicate]

This question already has answers here:
Break A Number Up To An Array of Individual Digits
(6 answers)
Closed 3 years ago.
Not sure how tag a question. I want to create an array of Int values from Int value. For example, if i have 1234 i want to output [1,2,3,4], for 8765 [8,7,6,5] etc. Function should look like:
private static func formAnArray(_ value: Int) -> [Int] {
// code
}
You can convert number to String and map it to array:
private static func formAnArray(_ value: Int) -> [Int] {
return String(value).compactMap { Int(String($0)) }
}
Another way (preferred for big numbers) is by using combination of % and /:
private static func formAnArray(_ value: Int) -> [Int] {
var value = value
var result: [Int] = []
while value > 0 {
result.insert(value % 10, at: 0)
value /= 10
}
return result
}
You can use compactMap to get and convert digits to an array of int
print(formAnArray(value: 1234))
func formAnArray(value: Int) -> [Int] {
let string = String(value)
return string.compactMap{Int(String($0))}
}

In didSet for an enum property in Swift is it possible to check if the new value is the same as the old one? [duplicate]

This question already has an answer here:
How may I test the equivalency of enumeration cases with associated values in Swift 4
(1 answer)
Closed 4 years ago.
Given the following example:
enum ViewState {
case idle
case loading
case caseWithAssociatedValue(String)
}
class View {
private var state: ViewState = .idle
func setState(to state: ViewState) {
guard state != self.state else { return }
self.state = state
}
}
I can't compare two properties of type ViewState and I can't use a raw value to compare as one of my cases has an associated value.
What I'm looking for is a way to check if the new value for state a new value or the same as the current value. Is this possible?
Use willSet and do something like this
enum State : Equatable {
case idle
case active
case done(String)
}
class test {
var x: State {
willSet {
if x != newValue {
print("\(x) -> \(newValue)")
}
}
}
init(_ x: State) {
self.x = x
}
}
let t = test(State.idle)
t.x = State.active
t.x = State.done("We're done")
Output is
idle -> active
active -> done("We\'re done")

Cannot convert type of Int to expected value [MyCustomType]

Xcode 8.3.3 is giving me this Swift 3 error on this line
values2[index] = nextValue(currentValue)
Cannot convert value of type 'Int' to expected argument type 'Card'
Here's my code:
//
// Card.swift
// match
//
// Created by quantum on 05/09/2017.
// Copyright © 2017 Quantum Productions. All rights reserved.
//
import UIKit
class Card: NSObject {
var quantity = 0
var fill = 0
var shape = 0
var color = 0
override var description : String {
return "Q" + String(quantity) + "/F" + String(fill) + "/S" + String(shape) + "/C" + String(color)
}
override init() {
super.init()
}
static func properties() -> [String] {
return ["quantity", "fill", "shape", "color"]
}
static func isMatch(cards: [Card]) -> Bool {
for property in self.properties() {
var sum = 0
for card in cards {
sum = sum + (card.value(forKey: property) as! Int)
}
if !([3, 6, 9, 7].contains(sum)) {
return false
}
}
return true
}
static func deck(_ values: [Int], _ index: Int, _ max: Int, _ acc: [Card]) -> [Card]{
let currentValue = values[index]
var values2 = values
if currentValue >= max {
if index == 0 {
return acc
}
values2[index] = 0
values2[index-1] = values2[index-1] + 1
return deck(values, index - 1, max, acc)
} else {
var acc2 = acc
let card = Card()
for (index, element) in self.properties().enumerated() {
card.setValue(values[index], forKey: element)
}
acc2.append(Card())
values2[index] = nextValue(Card())
return deck(values2, index, max, acc2)
}
}
func nextValue(_ v: Int) -> Int {
if (v == 0) {
return 1
} else if (v == 1) {
return 2
}
return 4
}
static func deck() -> [Card] {
return deck([1,1,1,1], 4, 3, [Card]())
}
}
this is inside of my Card class.
Strangely, if I try (this is wrong, I'm testing the compiler error)
values2[index] = nextValue(Card())
I get the error Cannot assign the value of type (Int) -> Int to type 'Int'.
Swift thinks my Card is an Int? I'm confused as to what's happening.
I expected to get the call nextvalue with the variable currentvalue, which should be an Int.
It's a bad error message from the compiler.
Your problem is that deck is declared static, but you're trying to call nextValue which is not declared static. This means that nextValue implicitly takes a hidden argument, self, but deck isn't providing it.
If you add static to the func nextValue declaration, it will work like you expect. (You'll get an error on the line referring to self.properties instead, but you'll be closer.)
To make this work properly, you probably want all these functions to be non-static instead. Just think about how this code gets called initially (i.e. how you get your first instance of Card).
A static method cannot call an instance method: the idea makes no sense, as there is no instance. Thus your reference to nextValue is impossible. That is why the line is problematic. How can a static method deck call an instance method nextValue?

Simpler way to alias instance variables to other instance variables in Swift?

Given the below struct in Swift, is there a more concise way to alias the instance variables x, y, and z to the properties of the three-tuple, _v?
Note: I realize that, of course, I could just declare these instance variables as Doubles and not need the tuple. However, the reason I'm doing it this way is so I can set three variables with a single-line statement like you will see in the init method and the below sample code.
Sample code with desired output of "1.0" "4.0":
var myVector = Vector3([1.0,2.0,3.0])
let x = myVector.x
print(x)
myVector.v = (4.0,5.0,6.0)
print(x)
The class:
struct Vector3 {
typealias V3 = (x:Double,y:Double,z:Double)
var v:V3 = (x:0.0,y:0.0,z:0.0)
var x:Double {
get {
return v.x
}
set(x) {
v.x = x
}
}
var y:Double {
get {
return v.y
}
set(y) {
v.y = y
}
}
var z:Double {
get {
return v.z
}
set(z) {
v.z = z
}
}
init(_ args:AnyObject...) {
if(args[0].isKindOfClass(NSArray)) {
v = (args[0][0].doubleValue,args[0][1].doubleValue,args[0][2].doubleValue)
}
else if(args.count == 3){
v = (args[0].doubleValue,args[1].doubleValue,args[2].doubleValue)
}
}
}
What I would like to be able to do is:
struct Vector3 {
typealias V3 = (x:Double,y:Double,z:Double)
var v:V3 = (x:0.0,y:0.0,z:0.0)
alias x = v.x
alias y = v.y
alias z = v.z
init(_ args:AnyObject...) {
if(args[0].isKindOfClass(NSArray)) {
v = (args[0][0].doubleValue,args[0][1].doubleValue,args[0][2].doubleValue)
}
else if(args.count == 3){
v = (args[0].doubleValue,args[1].doubleValue,args[2].doubleValue)
}
}
}
Of course that doesn't work. But is there another way to achieve the same thing?
Just do the opposite!
I realize that, of course, I could just declare these instance variables as Doubles and not need the tuple. However, the reason I'm doing it this way is so I can set three variables with a single-line statement like you will see in the init method and the below sample code.
If this is the reason then just do the opposite
struct Vector3 {
var x: Double
var y: Double
var z: Double
var coordinates: (Double, Double, Double) {
set { (x, y, z) = newValue }
get { return (x, y, z) }
}
}
Usage
var vector = Vector3(x: 1, y: 2, z: 3)
vector.x = 4
vector.coordinates // (4, 2, 3)
Final note
Your initializer could be improved in several ways.
Stop using NSArray, you are using Swift not Objective-C
Stop using isKindOfClass, use as? to perform a conditional cast
You have faith the objects inside the first array/s will have a doubleValue property. So I could easily crash your init passing something different right?
Now my question
What's wrong with the memberwise struct initializer?
It is automatically generated when you don't explicitly define an initializer for a struct, like in my previous code snipped.
Are you sure you want to define an initializer that literally accept any sort of objects an will crash with 99.99% of the combinations of values someone can pass to it?

Swift SequenceType not working

I'm trying to implement a SequenceType / GeneratorType example and getting an error that doesn't quite make sense.
Here's the code:
// Here's my GeneratorType - it creates a random-number Generator:
struct RandomNumberGenerator:GeneratorType {
typealias Element = Int
mutating func next() -> Element? {
return Int(arc4random_uniform(100))
}
}
When I call this (in Playgrounds) it works perfectly well:
var randyNum = RandomNumberGenerator()
randyNum.next() // this shows a valid random number in the Gutter
// And calling it from within a println also works:
println("randyNum = \(randyNum.next()!)")
So far so so good.
Next is the SequenceType:
struct RandomNumbersSequence:SequenceType {
typealias Generator = RandomNumberGenerator
var numberOfRandomNumbers:Int
init(maxNum:Int) {
numberOfRandomNumbers = maxNum
}
func generate() -> Generator {
for i in 1...numberOfRandomNumbers {
var randNum = Generator()
randNum.next()
return randNum
}
}
}
That's what's generating an error: 'Type RandomNumberSequence' does not conform to protocol 'SequenceType'. (Xcode is showing this error right on that first line of the declaration struct RandomNumbersSequence:SequenceType statement.)
I actually think the logic of my for loop may be wrong - meaning I won't get the results I actually want - but regardless, in terms of satisfying what the SequenceType Protocol is requiring, I think I got that much right.
So what's causing this error?
This isn’t quite how generators work. Assuming you want to serve up a set number of random numbers, you have the right idea about taking a maximum as a parameter, but you need to store that in the generator, as well, plus some state for where it is up to.
The idea with a generator is that it stores its state, and every time you call next() you return the next element. So if you want to generate a run of up to n numbers, you could do something like the following:
struct RandomNumberGenerator: GeneratorType {
let n: Int
var i = 0
init(count: Int) { self.n = count }
mutating func next() -> Int? {
if i++ < n {
return Int(arc4random_uniform(100))
}
else {
return nil
}
}
}
Note, you don’t need a for loop here. Just each time next() is called, i is incremented, until it reaches the max, then the generator starts returning nil.
The purpose of SequenceType is to serve up fresh generators:
struct RandomNumberSequence: SequenceType {
let n: Int
init(count: Int) { self.n = count }
func generate() -> RandomNumberGenerator {
return RandomNumberGenerator(count: n)
}
}
Given this, you can now use it to generate a sequence of a fixed number of random integers:
let seq = RandomNumberSequence(count: 3)
for x in seq {
// loops 3 times with x being a new random number each time
}
// every time you use seq, you get a new set of 3 numbers
",".join(map(seq,toString)) // prints 3 comma-separated random nums
// but when you create a generator, it gets “used up”
var gen = seq.generate()
println(gen.next()) // prints a random number
println(gen.next()) // prints another random number
println(gen.next()) // prints the third
println(gen.next()) // prints nil
println(gen.next()) // and will keep printing nil
gen = seq.generate()
println(gen.next()) // will print the first of a new set of 3 numbers
Creating these stateful generators is quite a common problem, so the standard library has a helper struct, GeneratorOf, that allows to you skip defining them. It takes a closure that each time it is called should return the next value to generate:
struct RandomNumbersSequence: SequenceType {
let maxNum: Int
init(maxNum: Int) { self.maxNum = maxNum }
func generate() -> GeneratorOf<Int> {
// counter to track how many have been generated
var n = 0
return GeneratorOf {
// the closure “captures” n
if n++ < self.maxNum {
return Int(arc4random_uniform(100))
}
else {
return nil
}
}
}
}
The error message you're seeing:
'Type RandomNumberSequence' does not conform to protocol 'SequenceType'
Always means that your class or struct is missing something that the protocol declares as required.
In this case, we're missing the generate() -> Generator method. "But, it's right there!" you say? Well, it is, but it's not compiling.
func generate() -> Generator {
for i in 1...numberOfRandomNumbers {
var randNum = Generator()
randNum.next()
return randNum
}
}
The problem is, what if you initialize your struct with numberOfRandomNumbers less than or equal to 0? Your loop executes zero times and generate can't return anything.
I'm not sure exactly what logic you're trying to to do in this loop, but we can fix the compilation errors by simply a adding a return statement that will return a Generator:
func generate() -> Generator {
for i in 1...numberOfRandomNumbers {
var randNum = Generator()
randNum.next()
return randNum
}
return Generator()
}
This won't do what you're trying to accomplish. This isn't how generators are supposed to work. But it will fix the generate() -> Generator method and allow your struct to now conform to the protocol.
With Swift 3, you can choose one of the three RandomNumbersSequence implementations in order to solve your problem.
1. Using a struct that conforms to Sequence protocol and a struct that conforms to IteratorProtocol protocol
The following Playground code shows how to implement a RandomNumbersSequence struct that conforms to Sequence and that uses a RandomNumbersIterator struct that conforms to IteratorProtocol protocol:
import Darwin // required for arc4random_uniform
struct RandomNumbersIterator: IteratorProtocol {
let maxNum: Int
var n = 0
init(maxNum: Int) {
self.maxNum = maxNum
}
mutating func next() -> Int? {
n += 1
return n <= self.maxNum ? Int(arc4random_uniform(10)) : nil
}
}
struct RandomNumbersSequence: Sequence {
let maxNum: Int
init(maxNum: Int) {
self.maxNum = maxNum
}
func makeIterator() -> RandomNumbersIterator {
return RandomNumbersIterator(maxNum: maxNum)
}
}
Usage #1:
for value in RandomNumbersSequence(maxNum: 3) {
print(value)
}
/*
may print:
5
7
3
*/
Usage #2:
let randomArray = Array(RandomNumbersSequence(maxNum: 3))
print(randomArray)
/*
may print: [7, 6, 1]
*/
Usage #3:
let randomSequence = RandomNumbersSequence(maxNum: 3)
var randomGenerator = randomSequence.makeIterator()
randomGenerator.next() // may return: 4
randomGenerator.next() // may return: 8
randomGenerator.next() // may return: 3
randomGenerator.next() // will return: nil
2. Using a struct that conforms to Sequence and IteratorProtocol protocols
The following Playground code shows how to implement a RandomNumbersSequence struct that conforms to Sequence and IteratorProtocol protocols:
import Darwin // required for arc4random_uniform
struct RandomNumbersSequence: Sequence, IteratorProtocol {
let maxNum: Int
var n = 0
init(maxNum: Int) {
self.maxNum = maxNum
}
mutating func next() -> Int? {
n += 1
return n <= self.maxNum ? Int(arc4random_uniform(10)) : nil
}
}
Usage #1:
for value in RandomNumbersSequence(maxNum: 3) {
print(value)
}
/*
may print:
5
7
3
*/
Usage #2:
let randomArray = Array(RandomNumbersSequence(maxNum: 3))
print(randomArray)
/*
may print: [7, 6, 1]
*/
Usage #3:
var randomSequence = RandomNumbersSequence(maxNum: 3)
randomSequence.next() // may return: 4
randomSequence.next() // may return: 8
randomSequence.next() // may return: 3
randomSequence.next() // will return: nil
3. Using AnyIterator and a struct that conforms to Sequence
As an alternative to the previous implementation, you can use AnyIterator<T> as the return type of the makeIterator method inside your Sequence protocol conforming struct. The following Playground code shows how to implement it with your RandomNumbersSequence struct:
import Darwin // required for arc4random_uniform
struct RandomNumbersSequence: Sequence {
let maxNum: Int
init(maxNum: Int) {
self.maxNum = maxNum
}
func makeIterator() -> AnyIterator<Int> {
var n = 0
let iterator: AnyIterator<Int> = AnyIterator {
n += 1
return n <= self.maxNum ? Int(arc4random_uniform(10)) : nil
}
return iterator
}
}
Usage #1:
for value in RandomNumbersSequence(maxNum: 3) {
print(value)
}
/*
may print:
5
7
3
*/
Usage #2:
let randomArray = Array(RandomNumbersSequence(maxNum: 3))
print(randomArray)
/*
may print: [7, 6, 1]
*/
Usage #3:
let randomSequence = RandomNumbersSequence(maxNum: 3)
let randomGenerator = randomSequence.makeIterator()
randomGenerator.next() // may return: 4
randomGenerator.next() // may return: 8
randomGenerator.next() // may return: 3
randomGenerator.next() // will return: nil