Question about printing out dictionary with multiple values by using forEach

Hi,

I have a code like this:

var dict: [String: [String: String]] = [
    "Mr" : ["Johnny": "Bravo"],
    "Ms" : ["Taylor": "Swift"]
]

dict.forEach { (key, firstAndLastName) in
    firstAndLastName.forEach { (firstName, lastName) in
        print("\(key),First name: \(firstName), Last name: \(lastName)")
    }
}

This code works fine, but I wonder if I could use parameters like $0 or $1 instead to print out the values instead.

From what I have tried, you can't do something like $1.forEach (not sure why)
If each key had only 1 value instead of two, I could just do print($0, $1)

Thanks!

1 Like

This is not in the standard library; you have to include it yourself:

public extension Dictionary where Value: Sequence {
  /// Flatten value sequences,
  /// pairing each value element with its original key.
  func flatMap() -> some Sequence<(key: Key, value: Value.Element)> {
    lazy.flatMap { key, value in value.lazy.map { (key, $0) } }
  }
}
dict.flatMap().forEach {
  print("\($0),First name: \($1.key), Last name: \($1.value)")
}

There's no way to avoid having names for the original pair, though, somewhere in code. (I.e. key, value above.) You can't refer to outer anonymous argument in an inner closure.


You can also avoid $1 but I that's even worse.

print("\($0.key),First name: \($0.value.value), Last name: \($0.value.value)")

Fundamentally, anonymous arguments are not helpful here.

  1. Do not use them.
dict.flatMap().forEach { title, name in
  print("\(title),First name: \(name.0), Last name: \(name.1)")
}
  1. Your data is not structured well. A dictionary known to have only one value should be a tuple or struct.
1 Like
  1. Your data is not structured well. A dictionary known to have only one value should be a tuple or struct.

Not sure what do you mean, my dictionary has 2 values for each key?

Also I'm confused about struct in this context, I understand tuples but how would struct be helpful here? I mean isn't it something completely different to a dictionary or a tuple?

I think he means it seems like you're trying to use a dictionary to describe a name, with one key being the first name and its value being the last name. So he was saying it would make more sense to do this:

var dict: [String: (firstName: String, lastName: String)] = [
  "Mr" : (firstName: "Johnny", lastName: "Bravo"),
  "Ms" : (firstName: "Taylor", lastName: "Swift")
]

And then it would be easy to do what you want.

dict.forEach { print("\($0), First name: \($1.firstName), Last name: \($1.lastName)") }
3 Likes

Thanks a lot, I had no idea (yet) that you can do this. :innocent: :smile: