5

With Swift is it possible to create a dictionary of [String:[Object]] from an array of objects [Object] using a property of those objects as the String key for the dictionary using swift's "map"?

class Contact:NSObject {

   var id:String = ""
   var name:String = ""
   var phone:String = ""

   init(id:String, name:String, phone:String){
      self.id = id
      self.name = name
      self.phone = phone
   }

}

var contactsArray:[Contact]
var contactsDict:[String:Contact]

contactsDict = (contactsArray as Array).map { ...WHAT GOES HERE... }
6
  • Calling map on an array returns another array, so no Commented Feb 4, 2016 at 17:12
  • 1
    You may use forEach and then populate a dictionary with the values. map returns an array - as @dan already pointed out. Commented Feb 4, 2016 at 17:16
  • If there is a better way than using "map" im open to that. Commented Feb 4, 2016 at 17:17
  • Currently i'm just looping over the items in the array and adding them that way. I just hoped there was a more concise solution. Commented Feb 4, 2016 at 17:19
  • 1
    Why is your contactsDict has [String: [Contact]]. Shouldn't it be [String: Contact]. And what field to use for the key of dictionary? Commented Feb 4, 2016 at 17:20

3 Answers 3

7

Let's say you want to use id as the key for the dictionary:

var contactsArray = [Contact]()
// add to contactsArray

var contactsDict = [String: Contact]()
contactsArray.forEach {
    contactsDict[$0.id] = $0
}

The difference between map and forEach is that map returns an array. forEach doesn't return anything.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks the forEach was what i was looking for.
2

You can achieve this via reduce in a one-line functional-style code:

let contactsDict = contactsArray.reduce([String:Contact]()) { var d = $0; d[$1.id] = $1; return d; }

This also keeps contactsDict immutable, which is the preferred way to handle variables in Swift.

Or, if you want to get fancy, you can overload the + operator for dictionaries, and make use of that:

func +<K,V>(lhs: [K:V], rhs: Contact) -> [K:V] {
    var result = lhs
    result[rhs.0] = rhs.1
    return result
}

let contactsDict = contacts.reduce([String:Contact]()) { $0 + ($1.id, $1) }

Comments

0

Swift 4

There's now a direct way to do this:

https://developer.apple.com/documentation/swift/dictionary/3127163-init

It's an initializer for Dictionary that lets you return a string key for each element in a Collection that specifies how it should be grouped in the resulting Dictionary.

2 Comments

The following link doesn't exist.
I updated the link above to one that works for this initializer mentioned by @Josh

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.