2

I have an array of objects which I want to store it in dictionary based on student id. In my dictionary my key is of type String and value is an array of string. How do I append the values in the array?

My student array:

var studentArray = [Student(id: '1', subject: 'History'), Student(id: '2', subject: 'History'), Student(id:'1', subject: 'Maths')]

My final dictionary should be like:

{'1': ['History', 'Maths'], '2': ['History']}

My code:

var dictionary = [String, [String]]()
for student in studentArray {
   dictionary.updateValue(student.subject, forKey: student.id)
}

This gives me output as:

{'1': ['Maths'], '2': ['History']}

I tried: dictionary[student.id].append([student.subject]) but this gives me nil output.

How do I append the value to an array inside the dictionary?

1

3 Answers 3

5

Everyone here is overcomplicating this. There's a dedicated API for this task lol

struct Student {
    let id: Int
    let subject: String
}

let students = [
    Student(id: 1, subject: "History"),
    Student(id: 2, subject: "History"),
    Student(id: 1, subject: "Maths")
]

let subjectsByStudentID = Dictionary
    .init(grouping: students, by: { $0.id })
    .mapValues { students in students.map { $0.subject } }

print(subjectsByStudentID) // => [2: ["History"], 1: ["History", "Maths"]]
Sign up to request clarification or add additional context in comments.

1 Comment

Great, I didn't knew that API.
3

EDIT: Thanks to Martin's comment. The snippet below is the the most succinct answer I can think of. I was initially coming at it from a wrong direction. and I was getting an error. See comments

struct Student { 
    let id: Int
    let subject : String
}

var studentArray = [Student(id: 1, subject: "History"), Student(id: 2, subject: "History"), Student(id:1, subject: "Maths")]

typealias Subject = String
var dict : [Int: [Subject]] = [:]

for student in studentArray {

    (dict[student.id, default: []]).append(student.subject)
}

print(dict)

Previous answers:

struct Student { 
    let id: Int
    let subject : String
}

var studentArray = [Student(id: 1, subject: "History"), Student(id: 2, subject: "History"), Student(id:1, subject: "Maths")]

typealias Subject = String
var dict : [Int: [Subject]] = [:]

for student in studentArray {
    var subjects = dict[student.id] ?? [String]()
    subjects.append(student.subject)
    dict[student.id] = subjects
}

print(dict)

Or you can do it this way:

struct Student { 
    let id: Int
    let subject : String
}

var studentArray = [Student(id: 1, subject: "History"), Student(id: 2, subject: "History"), Student(id:1, subject: "Maths")]

typealias Subject = String
var dict : [Int: [Subject]] = [:]

for student in studentArray {
    if let _ = dict[student.id]{
        dict[student.id]!.append(student.subject)
    }else{
        dict[student.id] = [student.subject]
    }
}

print(dict)

whichever you like

4 Comments

his code doesn't compile. he's using '. And it's an integer. I just assumed myself. typealias is just for improved readability...
Simpler: dict[student.id, default: []].append(student.subject) – compare stackoverflow.com/q/42486686/1187415.
@MartinR Aha. That's what I was trying to do. I was doing (dict[student.id] ?? [String]()).append(student.subject) which didn't work. I was getting the following error: cannot use mutating member on immutable value: '??' returns immutable value. I had to change my approach
let dict = students.reduce(into: [:]) { $0[$1.id, default: []].append($1.subject) }
0

Not tested but this should works:

var dictionary = [String: [String]]()

for student in studentArray {
    if dictionary[student.id] == nil {
        dictionary[student.id] = [String]()
    }
    dictionary[student.id]?.append(student.subject)
}

1 Comment

dictionary[student.id]? is nil

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.