Reputation: 428
I'm starting with Swift and I'm stuck with this problem for a while now. I'm trying to go through an array of cards and add them into a dictionary under a key that represents the turn they were played on.
I made a dictionary turnsWithCardsPlayed that should contain a key:value pairs like this - "Turn 2":[Card1, Card2, Card3]. The problem is if the key has no value associated with it yet, it doesn't append the card.
let turnsWithCardsPlayed = [String: [Card]]()
for card in arrayOfCards {
turnsWithCardsPlayed["Turn " + card.turn]!.append(card)
}
I solved the problem by including an if statement that checks if there is any value and if it is not, it creates a blank array and then appends the card. However the solution is clunky and too long in my opinion. Is there a better way to do it?
let turnsWithCardsPlayed = [String: [Card]]()
for card in arrayOfCards {
if var turnCardArray = turnsWithCardsPlayed["Turn " + card.turn] {
turnsWithCardsPlayed["Turn " + card.turn]!.append(card)
} else {
turnsWithCardsPlayed["Turn " + card.turn] = []
turnsWithCardsPlayed["Turn " + card.turn]!.append(card)
}
}
Thank you all :)
Upvotes: 2
Views: 141
Reputation: 59496
I know you have found your own solution, however please let me to describe a "swifter" and more functional programming approach. (IMHO of course).
Yeah, probably you have already corrected it. But in your code you are declaring turnsWithCardsPlayed
as constant
let turnsWithCardsPlayed = [String: [Card]]()
and then you are changing it. This is not allowed.
Let's assume Card
is a struct (maybe you have a class) declared as follow:
struct Card {
let turn: Int
}
Fine, lets add a computed property
to the struct (it will be useful very soon).
struct Card {
let turn: Int
var key: String { return "Turn \(turn)" }
}
This is just a style preference, however if you have an array of Card
I feel the natural name of the variable should be simply cards
. There's no point in repeating into the name of a variable the type of the variable itself.
So
let cards = [Card(turn: 0), Card(turn: 1), Card(turn: 1), Card(turn: 2), Card(turn: 1), Card(turn: 0)]
One thing we need to remove from your code is this guy !
because he has the power to crash your entire app. Every good Swift programmer should be really afraid of him.
Now, you want simply reorganize the elements in cards and append every card
to the correct slot of a dictionary. This can do with the reduce
method.
So
let turns = cards.reduce([String:[Card]]()) { (var accumulator, card) -> [String:[Card]] in
var list = accumulator[card.key] ?? [Card]()
list.append(card)
accumulator[card.key] = list
return accumulator
}
Hope this helps.
Upvotes: 1
Reputation: 2856
Similar to your solution, but using a ternary conditional instead and then pulling out the repeated append of the card, since it will be added regardless of if an array is needed to be added to the dictionary or not.
let turnsWithCardsPlayed = [String: [Card]]()
for card in arrayOfCards {
turnsWithCardsPlayed["Turn " + card.turn] != nil ? () : turnsWithCardsPlayed["Turn " + card.turn] = []
turnsWithCardsPlayed["Turn " + card.turn]!.append(card)
}
Upvotes: 0
Reputation: 70098
You could simplify it by using a ternary operator:
for card in arrayOfCards {
turnsWithCardsPlayed["Turn " + card.turn] == nil ? turnsWithCardsPlayed["Turn " + card.turn] = [card] : turnsWithCardsPlayed["Turn " + card.turn]!.append(card)
}
Upvotes: 2
Reputation: 1204
Array in Swift now is Struct
, because this it is always copy.
For your solution I recommend do it.
Mind you get a copy of Array and after change you commit your edit back to Dictionary.
let turnsWithCardsPlayed = [String: [Card]]()
for card in arrayOfCards {
//verify if have cards in dictionary and get it
if var cards = turnsWithCardsPlayed["Turn " + card.turn] {
//append element card in copied array
cards.append(card)
}else{
// if no has array create new and append new card
cards = []
cards.append(card)
}
//commit in dictionary your new or modified array
turnsWithCardsPlayed["Turn " + card.turn] = cards
}
Upvotes: 0