1

I have two arrays, from which one has to complete the other:

struct Score {
    let name: String
    let isComplete: Bool
    let finalScore: Int
}

var scores = [
    Score(name: "Steven", isComplete: false, finalScore: 12),
    Score(name: "Helen", isComplete: false, finalScore: 12),
    Score(name: "Adalbert", isComplete: false, finalScore: 12),
    Score(name: "Christian", isComplete: false, finalScore: 12),
    Score(name: "Susan", isComplete: false, finalScore: 3),
    Score(name: "Julia", isComplete: false, finalScore: 13),
    Score(name: "Robert", isComplete: false, finalScore: 13),
    Score(name: "Mercedes", isComplete: false, finalScore: 2),
    Score(name: "Gwendolin", isComplete: false, finalScore: 2),
]



struct Complete {
    let name: String
    let isComplete: Bool
}

var complete = [
    Complete(name: "Steven", isComplete: true),
    Complete(name: "Helen", isComplete: true),
    Complete(name: "Mercedes", isComplete: false),
    Complete(name: "Gwendolin", isComplete: true),
    // Name doesn´t exist in `score` and shouldn´t show up in the result:
    Complete(name: "nonexistingName", isComplete: true)
]

How could I complete the first array with the values from the second in a way that the result looks like this:

let result = [
    Score(name: "Steven", isComplete: true, finalScore: 12),
    Score(name: "Helen", isComplete: true, finalScore: 12),
    Score(name: "Adalbert", isComplete: false, finalScore: 12),
    Score(name: "Christian", isComplete: false, finalScore: 12),
    Score(name: "Susan", isComplete: false, finalScore: 3),
    Score(name: "Julia", isComplete: false, finalScore: 13),
    Score(name: "Robert", isComplete: false, finalScore: 13),
    Score(name: "Mercedes", isComplete: false, finalScore: 2),
    Score(name: "Gwendolin", isComplete: true, finalScore: 2),
]

Usually I would post a draft of my try, but since I´m quite new to swift, I have to admit I have no idea. Thanks for any advice.

1
  • A dictionary (mapping the name to the result) would be a better suited type for the scores. It allows to find and update entries efficiently. Commented Jun 26, 2017 at 21:26

2 Answers 2

3

Ultimately you should probably re-think your models, possibly with some sort of "Player" model so you don't have this kind of disconnect.

FWIW here's a safer/simpler way to do this with a dictionary:

struct Score {
    let name: String
    var isComplete: Bool
    let finalScore: Int
}

struct Complete {
    let name: String
    let isComplete: Bool
}

var scoresDictionary: [String : Score] = [:]

// this populates scoresDictionary with your array, keyed with the names
[   Score(name: "Steven", isComplete: false, finalScore: 12),
    Score(name: "Helen", isComplete: false, finalScore: 12),
    Score(name: "Adalbert", isComplete: false, finalScore: 12),
    Score(name: "Christian", isComplete: false, finalScore: 12),
    Score(name: "Susan", isComplete: false, finalScore: 3),
    Score(name: "Julia", isComplete: false, finalScore: 13),
    Score(name: "Robert", isComplete: false, finalScore: 13),
    Score(name: "Mercedes", isComplete: false, finalScore: 2),
    Score(name: "Gwendolin", isComplete: false, finalScore: 2),
    ].forEach { scoresDictionary[$0.name] = $0}

let complete = [
    Complete(name: "Steven", isComplete: true),
    Complete(name: "Helen", isComplete: true),
    Complete(name: "Mercedes", isComplete: false),
    Complete(name: "Gwendolin", isComplete: true),
    // Name doesn´t exist in `score` and shouldn´t show up in the result:
    Complete(name: "nonexistingName", isComplete: true)
]

//Updates only the found values in scoresDictionary
complete.forEach { scoresDictionary[$0.name]?.isComplete = $0.isComplete }

// The dictionary is updated, but in case you just want the Scores, this gives you an array
let result: [Score] = Array(scoresDictionary.values)
Sign up to request clarification or add additional context in comments.

9 Comments

let result: [Score] = Array(scoresDictionary.values) is getting the Score values from the dictionary and putting them in an array
Thanks a lot! I just tried with a very big Array. It´s working absolutely fine.
@ PEEJWEEJ: Yeah, I just oversaw it in the hurry.
@ PEEJWEEJ: Would it be even better to setup the [Complete] as Dictionary as well? Like [String: Bool]?
Keep in mind these assume unique names. If that's a problem I would suggest switching to more of a database model with UIDs
|
0

Basically we just iterate scores, looking for a matching Complete. If we find one, we return a Score with the attribute isComplete set true or false. If we don't find one, we return the original Score unchanged.

var final: [Score] = scores.map { aScore in

    let comp = complete.first { aScore.name == $0.name }
    if let comp = comp {
        return Score(name: aScore.name, isComplete: comp.isComplete || aScore.isComplete, finalScore: aScore.finalScore)
    }
    return aScore
}

final.forEach {
    print($0.name, $0.isComplete, $0.finalScore)
}

Prints:

Steven true 12
Helen true 12
Adalbert false 12
Christian false 12
Susan false 3
Julia false 13
Robert false 13
Mercedes false 2
Gwendolin true 2

6 Comments

"filter + first" can be simplified using first(where:)
I just tried it out and it´s just awesome! Need a little time to exactly understand how it works. Thank you very much! One more question: Is this method iterating scores for every single complete value? So in this case 5 times? Because my Score array is quite big.
@MartinR thanks, updated! @Josch Hazard, no, it iterates scores once, potentially iterating the whole complete array for each value in scores. So if scores is large, and complete relatively short, this should be a pretty fast solution.
It searches complete for it's match with every item from scores. This works, but is very inefficient.
It would actually be more efficient if the iterations were swapped
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.