Swift: How to handle optional from Array.randomElement() CS193p 2021 - swift

(Non student) attempting 2021 programming assignment 2. I've got the app working with .randomElement, but obviously this allows multiple cards of the same emoji to be generated. I tried removing that element from my areay of emojis, but I can't handle the optional. any extra hints?
Be able to generate cards without duplicates
The following code is what I have so far. Part of it should look familiar from the lectures. my attempt to unwrap doesn't actually compile as shown here. I'm pretty sure I'm close with this..
static func createMemoryGame( chosenTheme : inout EmojiMemoryGame.gameTheme ) -> MemoryGame<String> {
MemoryGame<String>(numberOfPairsOfCards: chosenTheme.themeNoOfPairs) { _ in
var x = chosenTheme.emojis.randomElement()
if let safex = x {
if chosenTheme.emojis.count > 0 {
if let index = chosenTheme.emojis.firstIndex(of: safex ) {
chosenTheme.emojis.remove(at: index)
}//chosenTheme.emojis[pairIndex]
}
}
return safex
}
}

Related

What does `outlined init with copy of protocol` mean?

I wrote very simple piece of code in Swift:
protocol MultiplyByTwoProtocol {
func multiply() -> Int
}
class MultiplyByTwoClass: MultiplyByTwoProtocol {
private let n: Int
init(n: Int) { self.n = n }
func multiply() -> Int { return 2 * n }
}
class DynamicDispatchSwift {
private let items: [MultiplyByTwoProtocol]
init(n: Int) {
self.items = Array<Int>.generate(size: n).map(MultiplyByTwoClass.init)
}
func run() {
items.forEach { input in
_ = input.multiply()
}
}
}
(btw generate method for Array just creates an array of random Ints)
Then, I run that code in Instruments and I got following results:
As you can see, almost half of the time takes entry called outlined init with copy of MultiplyByTwoProtocol. Does anyone know what it is?
Thanks for your help.
I just ran into outlined init with copy of ... as the top of a stack trace for crashes coming from an app built with release configuration. I found that turning off the compiler optimization settings would prevent the crash. Ultimately I also found an equivalent syntax for the code the stack trace pointed to, that the optimizer was having problems with, that did not cause crashes and was able to turn optimization back on.
In my case the line of code causing the issue was accessing a static constant inside a for loop. Assigning that same static constant to nothing just prior to the loop fixed the crash, as in this example:
let _ = Foo.fooConstant // This line fixed the crash
for index in 0..<values.count {
let someBar = Bar(foo: .fooConstant)
...
}

Using an instance in a function

I’m new to Swift so I’ve been using the Swift Playgrounds app. On level 2 “Two Experts”, I initialized two experts:
let expert1 = Expert()
let expert2 = Expert()
What I wanted to do was create a function and pass whichever instance into it, access it’s methods etc, something like:
func actions(who: Item, distance: Int, turn: String) {
for 0 to distance {
who.moveforward()
}
ff turn == “Left” {
who.turnleft()
} else if turn == “Right” {
who.turnright()
}
}
Where who is expert1 or expert2.
I couldn’t find a way of doing this so had to write the same actions twice:
Func actions(who: String, distance: Int, turn:String) {
if who == “expert1” {
for 0 to distance {
expert1.moveforward()
} Etc
if who == “expert2” {
for 0 to distance {
expert2.moveforward()
} Etc
Is there a way of passing an instance into a function then perform certain actions if it’s of a particular class?
Since your experts is of type Expert, then the who parameter in your actions method should be of type Expert, if I understand the code correctly. Then you don't need two functions for each of the Experts. Let me know if I understood you correctly, and if it worked out.
Update
#Alexander mentioned that you can also have these methods in an extension on Expert, like so:
extension Expert {
func actions(distance: Int, turn: String) {
// Add method code here
}
}
When adding the method in an extension, every Expert object can use the method. So you could write expert1.actions(1, "Left") or something like that. Here's a link to the official Swift Programming Language guide about extensions.

How to create a generator in Swift?

Can I create a generator in Swift?
With iterator, I need store intermediate results, for example:
struct Countdown: IteratorProtocol, Sequence {
private var value = 0
init(start: Int) {
self.value = start
}
mutating func next() -> Int? {
let nextNumber = value - 1
if nextNumber < 0 {
return nil
}
value -= 1
return nextNumber
}
}
for i in Countdown(start: 3) {
print(i)
} // print 1 2 3
In this example, I need store the value.
In my situation, I want to use generator instead of iterator, because I don't want store the intermediate results of my sequence in each next.
Understanding how generators work (and why they are less important in swift) is at first difficult coming from Python.
Up to Swift v2.1 there was a protocol called GeneratorType. This was renamed to IteratorProtocol in Swift v3.0+. You can conform to this protocol to make your own objects that do just-in-time computations similar to what can be done in Python.
More information can be found in the Apple Documentation: IteratorProtocol
A simple example from IteratorProtocol page:
struct CountdownIterator: IteratorProtocol {
let countdown: Countdown
var times = 0
init(_ countdown: Countdown) {
self.countdown = countdown
}
mutating func next() -> Int? {
let nextNumber = countdown.start - times
guard nextNumber > 0
else { return nil }
times += 1
return nextNumber
}
}
let threeTwoOne = Countdown(start: 3)
for count in threeTwoOne {
print("\(count)...")
}
// Prints "3..."
// Prints "2..."
// Prints "1..."
However, you need to think about why you are using a generator:
Swift automatically does something "called copy on write." This means that many of the cases that use a Python generator to avoid the large copying cost of collections of objects (arrays, lists, dictionaries, etc) are unnecessary in Swift. You get this for free by using one of the types that use copy on write.
Which value types in Swift supports copy-on-write?
It is also possible to use a wrapper to force almost any object to be copy on write, even if it is not part of a collection:
How can I make a container with copy-on-write semantics?
The optimizations in swift usually mean that you do not not have to write generators. If you really do need to (usually because of data heavy, scientific calculations) it is possible as above.
Based on the code you provided and the little bit knowledge of generators that I do have, you can do something like
struct Countdown {
private var _start = 0
private var _value = 0
init(value: Int) {
_value = value
}
mutating func getNext() -> Int? {
let current = _start
_start += 1
if current <= _value {
return current
} else {
return nil
}
}
}
and then wherever you want to use it, you can do something like
var counter = Countdown(value: 5)
while let value = counter.getNext() {
print(value)
}
Walter provides a lot of good information, and generally you shouldn't be doing this in Swift, but even if you wanted an Iterator, the right way to do it is with composition, not by building your own. Swift has a lot of existing sequences that can be composed to create what you want without maintaining your own state. So in your example, you'd differ to a range's iterator:
struct Countdown: Sequence {
private var value = 0
init(start: Int) {
self.value = start
}
func makeIterator() -> AnyIterator<Int> {
return AnyIterator((0..<value).reversed().makeIterator())
}
}
for i in Countdown(start: 3) {
print(i)
} // print 1 2 3
Something has to keep the state; that's the nature of these kinds of functions (even in a world with coroutines). It's fine not to maintain it directly; just delegate to a more primitive type. Swift has a couple of dozen built-in Iterators you can use to build most things you likely need, and any iterator can be lifted to an AnyIterator to hide the implementation details. If you have something custom enough that it really requires a next(), then yes, storing the state is your problem. Something has to do it. But I've found this all to be extremely rare, and often suggests over-design when it comes up.
I have a solution similar to above, but with a slightly more "yield-y" feeling to it.
struct Countdown
{
static func generator(withStart: Int) -> () -> Int?
{
var start = withStart + 1
return {
start = start - 1
return start > 0 ? start : nil
}
}
}
let countdown = Countdown.generator(withStart: 5)
while let i = countdown()
{
print ("\(i)")
}

Avoid multiplying of values while appending in object

I would like to ask how to corret my issue. I just simply append some "portals" to a depending country. EACH "portal" which comes more than once, I dont want to append.
I have following class definitions:
class cls_main{
var countries:[cls_country]!
init() {
countries = [cls_country]()
}
// "add Country"
func addCountry(iCountry:cls_country) {
countries.append(iCountry)
}
}
class cls_country{
var countryName:String!
var portals:[cls_portal]!
init() {
portals = [cls_portal]()
}
// "add Portal"
func addPortal(portName:String) {
var tmpPortal = cls_portal()
tmpPortal.portalName = portName
println("-->Input Portal: \(tmpPortal.portalName)")
if portals.count == 0 {
portals.append(tmpPortal)
} else {
for port in portals {
if port.portalName == portName {
println("SAME INPUT, DONT SAVE")
} else {
portals.append(tmpPortal)
}
}
}
}
func arrayCount(){
println("Portals : \(portals.count)")
}
}
class cls_portal{
var portalName:String!
}
And so I will call it:
var MAIN = cls_main()
var country = cls_country()
country.countryName = "USA"
country.addPortal("Dance")
country.addPortal("Dance") // Should not be appended...
country.addPortal("Hike")
country.addPortal("Swim")
country.addPortal("Play")
MAIN.addCountry(country)
country = cls_country()
After adding the values Im looping over the values and print them. The result would be like this:
Loop:
for country in MAIN.countries {
println("COUNTRY: \(country.countryName)")
if country.countryName == "USA" {
for portal in country.portals {
println(" -> PORTAL : \(portal.portalName)")
}
country.arrayCount()
}
}
Result:
-->Input Portal: Dance
-->Input Portal: Dance
SAME INPUT, DONT SAVE
-->Input Portal: Hike
-->Input Portal: Swim
-->Input Portal: Play
COUNTRY: USA
-> PORTAL : Dance
-> PORTAL : Hike
-> PORTAL : Swim
-> PORTAL : Swim
-> PORTAL : Play
-> PORTAL : Play
-> PORTAL : Play
-> PORTAL : Play
Portals : 8
So why every and each portal will be multiplying at the end? Thank you very much.
In your search loop, you are deciding after looking at each element whether tmpPortal is in your portals or not. You need to potentially look at all of the items before you can make that decision. Add a variable found to note that it has been found. You can break out of the loop once you've found the item.
if portals.count == 0 {
portals.append(tmpPortal)
} else {
var found = false
for port in portals {
if port.portalName == portName {
println("SAME INPUT, DONT SAVE")
found = true
// found it, stop searching
break
}
}
if !found {
portals.append(tmpPortal)
}
}
If you are using Swift 1.2 a better solution to this would by using Set so you wont need addPortal method at all. Set offers almost the same functionality as array but it simply does not store same values. Be aware that in order to make it work with set your cls_portal class must adopt hashable and equitable protocols
A set stores distinct values of the same type in a collection with no defined ordering. You can use sets as an alternative to arrays when the order of items is not important, or when you need to ensure that an item only appears once.
You’re looping multiple times over the array, checking it. But for every element that isn’t a match, you are inserting the portal. So when there are 3 other non-matching elements, you insert a portal 3 times.
Try replacing your inner loop (everything from if portals.count == all the way down to the end of the else) with this:
if !contains(portals, { $0.portalName == portName }) {
portals.append(tmpPortal)
}
contains is a function that checks if a collection (like your array of portals) contains an entry that matches a certain criteria. The criteria is determined by a closure, in this case one that checks if the element’s portal name matches the one you’re checking for. Try reading this link if you’re not familiar with closures – they can be very helpful in Swift.
P.S. there are a few other things in your code you might want to reconsider. For example, it’s best to avoid using implicitly-unwrapped optionals (i.e. types with a ! after them) like this. Implicit optionals are in Swift for some very specific purposes, which it doesn’t look like apply in your code. Especially not with arrays - better to just make the array empty on initialization. But also, if it makes no sense to have a portal without a country name, you make it part of the initializer.
So instead of this:
class cls_country{
var countryName:String!
var portals:[cls_portal]!
init() {
portals = [cls_portal]()
}
}
// and in use:
var tmpPortal = cls_portal()
tmpPortal.portalName = portName
you could write this:
class cls_country {
var portals = [cls_country]()
// consider let not var if a country will never
// need to change its name:
let countryName: String
init(countryName: String) {
self.countryName = countryName
//no need to initialize portals in init
}
}
// then later, in use:
var tmpPortal = cls_portal(countryName: portName)

What is the shortest way to run same code n times in Swift?

I have a code that I need to run exactly n times in Swift. What is the shortest possible syntax for that?
I am currently using the for loop but it is a lot of typing.
for i in 0..<n { /* do something */ }
Is there a shorter/nicer way for running same code n times in Swift?
Speaking of syntax, you might define your own shortest syntax:
extension Int {
func times(_ f: () -> ()) {
if self > 0 {
for _ in 0..<self {
f()
}
}
}
func times(_ f: #autoclosure () -> ()) {
if self > 0 {
for _ in 0..<self {
f()
}
}
}
}
var s = "a"
3.times {
s.append(Character("b"))
}
s // "abbb"
var d = 3.0
5.times(d += 1.0)
d // 8.0
Sticking with a for loop - you could extend Int to conform to SequenceType to be able to write:
for i in 5 { /* Repeated five times */ }
To make Int conform to SequenceType you'll could do the following:
extension Int : SequenceType {
public func generate() -> RangeGenerator<Int> {
return (0..<self).generate()
}
}
You have several ways of doing that:
Using for loops:
for i in 1...n { `/*code*/` }
for i = 0 ; i < n ; i++ { `/*code*/` }
for i in n { `/*code*/` }
using while loops:
var i = 0
while (i < n) {
`/*code*/`
` i++`
}
var i = 0
repeat {
` /*code*/`
`i++`
} while(i <= n)
for _ in 1...5 {
//action will be taken 5 times.
}
you could use functional programming on a range instead of a loop, for shorter and "nicer" syntax for example
(0..<n).forEach{print("Index: \($0)")}
Other answers mention defining your own syntax for that. So - that can be fine for a tiny personal project, or as a learning experience. But defining your own syntax for something so trivial and basic in a large project would be maintenance and readability hell.
You could do something like this:
10⨉{ print("loop") }
Using a custom operator and an extension on Int:
infix operator ⨉ // multiplication sign, not lowercase 'x'
extension Int {
static func ⨉( count:Int, block: () ->Void ) {
(0..<count).forEach { _ in block() }
}
}
ABakerSmith's answer updated for Swift 4:
extension Int: Sequence {
public func makeIterator() -> CountableRange<Int>.Iterator {
return (0..<self).makeIterator()
}
}
Use:
for i in 5 {
//Performed 5 times
}
Shorter and (I think) clearer:
for i in 1...n { } // note: this will fail if n < 1
or
for i in n { }
In Swift, what you have is the shortest syntax for performing a loop operation.
Swift provides two kinds of loop that perform a set of statements a
certain number of times:
The for-in loop performs a set of statements for each item in a
sequence.
The for loop performs a set of statements until a specific
condition is met.
If you want to run it infinite times, well try using a while.
There are a lot of answers here, highlighting just how creative you can be, with Swift.
I needed an array so I did this
extension Int {
func of<T>(iteration: (Int) -> T) -> [T] {
var collection = [T]()
for i in 0..<self {
collection.append(iteration(i))
}
return collection
}
}
fun strings() -> [String] {
return 4.of { "\($0) teletubby" }
}
for-loops are a common way to repeat code. Here is an example of using a for-loop to hide six outlets, versus writing the same code for six outlets. Plus if you make another outlet all you have to do is add it to the array.
let array = [outLet0, outlet1, outlet2, outLet3, outLet4, outLet5]
for outlet in array {
outlet.hidden = true
}
Versus writing it like this:
outlet0.hidden = true
outlet1.hidden = true
outlet2.hidden = true
outlet3.hidden = true
outlet4.hidden = true
outlet5.hidden = true
ONLY 5 CHARACTERS (not including n or code)
r(){}
If you're just testing things and need a REALLY short line, try this. Emphasis on using this for testing, not in production, because no one will know what is going on without documentation.
define this somewhere globally
func r(_ n : UInt, _ c: #escaping () -> Void) { for _ in 0..<n { c() } }
call this when you want to run it
r(5) { /*code*/ }
Swift is so awesome, just write your own function or extension and you got it ;) 100 of options there, everyone can do it its own way just look at those answers here.
Or better, write it as you already do, as is common when apps are build in team, as everyone would do it differently anyway and all projects need those extension to be written again or own libs to have and maintain just for stupid thing, that you can write just by some standard way, as you already did with your for loop.
The only loop shorter than that is an infinite while loop:
while (true) {
}
But you would still have to increase a counter and check it in the loop to break the loop, and in the end it wouldn't be shorter.