map-like operation that returns a dictionary


(Kenny Leung) #1

Hi All.

I find that instead of using map() on arrays, I more often use an operation that returns a dictionary from an array. A common case is fetching an array of data, then creating a local cache of it indexed by ID.

Is there a name for this operation? Is this something that others would like to see added to the standard library?

-Kenny


(Zhao Xin) #2

You can use dictionary in a map. You just ignore the return value of the
map.

var dic = [Int:String]()
var index = 0

["John", "Mike", "Amy", "Kavin"].map {
    dic.updateValue($0, forKey: index)
    index += 1
}

print(dic) // [2: "Amy", 0: "John", 1: "Mike", 3: "Kavin"]

zhaoxin

···

On Mon, Jan 11, 2016 at 1:50 AM, Kenny Leung via swift-evolution < swift-evolution@swift.org> wrote:

Hi All.

I find that instead of using map() on arrays, I more often use an
operation that returns a dictionary from an array. A common case is
fetching an array of data, then creating a local cache of it indexed by ID.

Is there a name for this operation? Is this something that others would
like to see added to the standard library?

-Kenny

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao


(Brent Royal-Gordon) #3

If there was an initialiser for Dictionary which took an Array or EnumerateSequence, that might be useful. I'm not sure how I'd attempt to write such an initialiser though.

Well, we can begin with a simple "initialize from key-value tuple sequence" initializer:

  init?<Sequence: SequenceType where Sequence.Generator.Element == Element>(_ seq: Sequence) {
    self.init()
    for (key, value) in seq {
      let oldValue = updateValue(value, forKey: key)
      
      // Did this key already have a value?
      if oldValue != nil {
        return nil
      }
    }
  }

Now you can say things like:

  Dictionary(array.map { ($0.identifier, $0) })

If you want to special-case "invert a collection into an element-to-index dictionary", you could add something like this:

  init?<Collection: CollectionType where Collection.Generator.Element == Key, Collection.Index == Value>(ofIndices collection: Collection) {
    self.init(zip(collection, collection.indices))
  }

Unfortunately, this specific implementation emits a bizarre error on the `collection.indices` expression, complaining that "value of type 'Collection' has no member 'IntegerLiteralType'"; I must be doing something wrong. But a properly working version of that would allow you to say:

  Dictionary(ofIndices: array)

These two initializers might be useful enough to be worth including in the standard library.

···

--
Brent Royal-Gordon
Architechies


(Jo Albright) #4

Possible solution to do what you are wanting.

extension Array {
    
    func map<T>(var d: [String:T] = [:], @noescape transform: (Int,Array.Generator.Element) throws -> [String:T]) rethrows -> [String:T] {
        
        for (i,item) in self.enumerate() {
            
            try d += transform(i,item)
            
        }
        
        return d
        
    }
    
}

func += <T>(inout lhs: [String:T], rhs: [String:T]) -> [String:T] {
    
    for (k,v) in rhs { lhs[k] = v }; return lhs
    
}

let names = ["Jo","Jenna","Jake","Julie"]
let ages = [32,20,46,39]
    
let namesInfo1 = names.map { ["\($0)": $1] }
namesInfo1 // ["2": "Jake", "1": "Jenna", "0": "Jo", "3": "Julie"]

let namesInfo2 = names.map(["6":"Jim"]) { ["\($0)": $1] }
namesInfo2 // ["2": "Jake", "1": "Jenna", "0": "Jo", "6": "Jim", "3": "Julie"]

let namesInfo3 = names.map { [$1: ages[$0]] }
namesInfo3 // ["Jenna": 20, "Jo": 32, "Jake": 46, "Julie": 39]

Designer . Developer .  Nerd
Jo Albright

···

On Jan 10, 2016, at 4:25 PM, Loïc Lecrenier via swift-evolution <swift-evolution@swift.org> wrote:

I think this is O(n^2) though, so it’s not really usable.
(It is destroying and copying the dictionary each time)

There really isn’t anything like map for dictionaries.
I am not convinced we should add it to the standard library though.

On Jan 10, 2016, at 10:19 PM, Ian Ynda-Hummel via swift-evolution <swift-evolution@swift.org> wrote:

I think this probably wants to be a `reduce`. Given the above example:

   ["John", "Mike", "Amy", "Kavin"].enumerate().reduce([Int: String]()) { (var dictionary, data) in
       dictionary[data.index] = data.element
       return dictionary
   }

Which means you create an immutable dictionary with `let`. This could probably look nicer, but I think it illustrates the idea, at least.

-Ian

On Sun, Jan 10, 2016 at 2:46 PM Craig Cruden via swift-evolution <swift-evolution@swift.org> wrote:
There is no equivalent to something like

array.zipWithIndex.toMap (or in this case array.zipWithIndex.toDictionary // where zipWithIndex creates tuples with the index - a specialized case of zip for Arrays with indexes.

On 2016-01-11, at 2:41:59, Ross O'Brien via swift-evolution <swift-evolution@swift.org> wrote:

Or an enumeration followed by a forEach.
["John", "Mike", "Amy", Kavin"].enumerate().forEach {
   dic[$0] = $1
}
That said, it requires creating a dictionary var first, not a let. If there was an initialiser for Dictionary which took an Array or EnumerateSequence, that might be useful. I'm not sure how I'd attempt to write such an initialiser though.

On Sun, Jan 10, 2016 at 7:08 PM, Donnacha Oisín Kidney <swift-evolution@swift.org> wrote:
I think that use of map is generally discouraged. forEach would probably be more explicit, or a for-loop.

On 10 Jan 2016, at 18:58, 肇鑫 via swift-evolution <swift-evolution@swift.org> wrote:

You can use dictionary in a map. You just ignore the return value of the map.

var dic = [Int:String]()
var index = 0

["John", "Mike", "Amy", "Kavin"].map {
   dic.updateValue($0, forKey: index)
   index += 1
}

print(dic) // [2: "Amy", 0: "John", 1: "Mike", 3: "Kavin"]

zhaoxin

On Mon, Jan 11, 2016 at 1:50 AM, Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:
Hi All.

I find that instead of using map() on arrays, I more often use an operation that returns a dictionary from an array. A common case is fetching an array of data, then creating a local cache of it indexed by ID.

Is there a name for this operation? Is this something that others would like to see added to the standard library?

-Kenny

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Donnacha Oisín Kidney) #5

I think that use of map is generally discouraged. forEach would probably be more explicit, or a for-loop.

···

On 10 Jan 2016, at 18:58, 肇鑫 via swift-evolution <swift-evolution@swift.org> wrote:

You can use dictionary in a map. You just ignore the return value of the map.

var dic = [Int:String]()
var index = 0

["John", "Mike", "Amy", "Kavin"].map {
    dic.updateValue($0, forKey: index)
    index += 1
}

print(dic) // [2: "Amy", 0: "John", 1: "Mike", 3: "Kavin"]

zhaoxin

On Mon, Jan 11, 2016 at 1:50 AM, Kenny Leung via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hi All.

I find that instead of using map() on arrays, I more often use an operation that returns a dictionary from an array. A common case is fetching an array of data, then creating a local cache of it indexed by ID.

Is there a name for this operation? Is this something that others would like to see added to the standard library?

-Kenny

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Ross O'Brien) #6

Or an enumeration followed by a forEach.
["John", "Mike", "Amy", Kavin"].enumerate().forEach {
    dic[$0] = $1
}
That said, it requires creating a dictionary var first, not a let. If there
was an initialiser for Dictionary which took an Array or EnumerateSequence,
that might be useful. I'm not sure how I'd attempt to write such an
initialiser though.

···

On Sun, Jan 10, 2016 at 7:08 PM, Donnacha Oisín Kidney < swift-evolution@swift.org> wrote:

I think that use of map is generally discouraged. forEach would probably
be more explicit, or a for-loop.

On 10 Jan 2016, at 18:58, 肇鑫 via swift-evolution < > swift-evolution@swift.org> wrote:

You can use dictionary in a map. You just ignore the return value of the
map.

var dic = [Int:String]()
var index = 0

["John", "Mike", "Amy", "Kavin"].map {
    dic.updateValue($0, forKey: index)
    index += 1
}

print(dic) // [2: "Amy", 0: "John", 1: "Mike", 3: "Kavin"]

zhaoxin

On Mon, Jan 11, 2016 at 1:50 AM, Kenny Leung via swift-evolution < > swift-evolution@swift.org> wrote:

Hi All.

I find that instead of using map() on arrays, I more often use an
operation that returns a dictionary from an array. A common case is
fetching an array of data, then creating a local cache of it indexed by ID.

Is there a name for this operation? Is this something that others would
like to see added to the standard library?

-Kenny

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Ian Ynda-Hummel) #7

I think this probably wants to be a `reduce`. Given the above example:

    ["John", "Mike", "Amy", "Kavin"].enumerate().reduce([Int: String]()) {
(var dictionary, data) in
        dictionary[data.index] = data.element
        return dictionary
    }

Which means you create an immutable dictionary with `let`. This could
probably look nicer, but I think it illustrates the idea, at least.

-Ian

···

On Sun, Jan 10, 2016 at 2:46 PM Craig Cruden via swift-evolution < swift-evolution@swift.org> wrote:

There is no equivalent to something like

array.zipWithIndex.toMap (or in this case array.zipWithIndex.toDictionary
// where zipWithIndex creates tuples with the index - a specialized case of
zip for Arrays with indexes.

On 2016-01-11, at 2:41:59, Ross O'Brien via swift-evolution < > swift-evolution@swift.org> wrote:

Or an enumeration followed by a forEach.
["John", "Mike", "Amy", Kavin"].enumerate().forEach {
    dic[$0] = $1
}
That said, it requires creating a dictionary var first, not a let. If
there was an initialiser for Dictionary which took an Array or
EnumerateSequence, that might be useful. I'm not sure how I'd attempt to
write such an initialiser though.

On Sun, Jan 10, 2016 at 7:08 PM, Donnacha Oisín Kidney < > swift-evolution@swift.org> wrote:

I think that use of map is generally discouraged. forEach would probably
be more explicit, or a for-loop.

On 10 Jan 2016, at 18:58, 肇鑫 via swift-evolution < >> swift-evolution@swift.org> wrote:

You can use dictionary in a map. You just ignore the return value of the
map.

var dic = [Int:String]()
var index = 0

["John", "Mike", "Amy", "Kavin"].map {
    dic.updateValue($0, forKey: index)
    index += 1
}

print(dic) // [2: "Amy", 0: "John", 1: "Mike", 3: "Kavin"]

zhaoxin

On Mon, Jan 11, 2016 at 1:50 AM, Kenny Leung via swift-evolution < >> swift-evolution@swift.org> wrote:

Hi All.

I find that instead of using map() on arrays, I more often use an
operation that returns a dictionary from an array. A common case is
fetching an array of data, then creating a local cache of it indexed by ID.

Is there a name for this operation? Is this something that others would
like to see added to the standard library?

-Kenny

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Loïc Lecrenier) #8

I think this is O(n^2) though, so it’s not really usable.
(It is destroying and copying the dictionary each time)

There really isn’t anything like map for dictionaries.
I am not convinced we should add it to the standard library though.

···

On Jan 10, 2016, at 10:19 PM, Ian Ynda-Hummel via swift-evolution <swift-evolution@swift.org> wrote:

I think this probably wants to be a `reduce`. Given the above example:

    ["John", "Mike", "Amy", "Kavin"].enumerate().reduce([Int: String]()) { (var dictionary, data) in
        dictionary[data.index] = data.element
        return dictionary
    }

Which means you create an immutable dictionary with `let`. This could probably look nicer, but I think it illustrates the idea, at least.

-Ian

On Sun, Jan 10, 2016 at 2:46 PM Craig Cruden via swift-evolution <swift-evolution@swift.org> wrote:
There is no equivalent to something like

array.zipWithIndex.toMap (or in this case array.zipWithIndex.toDictionary // where zipWithIndex creates tuples with the index - a specialized case of zip for Arrays with indexes.

On 2016-01-11, at 2:41:59, Ross O'Brien via swift-evolution <swift-evolution@swift.org> wrote:

Or an enumeration followed by a forEach.
["John", "Mike", "Amy", Kavin"].enumerate().forEach {
    dic[$0] = $1
}
That said, it requires creating a dictionary var first, not a let. If there was an initialiser for Dictionary which took an Array or EnumerateSequence, that might be useful. I'm not sure how I'd attempt to write such an initialiser though.

On Sun, Jan 10, 2016 at 7:08 PM, Donnacha Oisín Kidney <swift-evolution@swift.org> wrote:
I think that use of map is generally discouraged. forEach would probably be more explicit, or a for-loop.

On 10 Jan 2016, at 18:58, 肇鑫 via swift-evolution <swift-evolution@swift.org> wrote:

You can use dictionary in a map. You just ignore the return value of the map.

var dic = [Int:String]()
var index = 0

["John", "Mike", "Amy", "Kavin"].map {
    dic.updateValue($0, forKey: index)
    index += 1
}

print(dic) // [2: "Amy", 0: "John", 1: "Mike", 3: "Kavin"]

zhaoxin

On Mon, Jan 11, 2016 at 1:50 AM, Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:
Hi All.

I find that instead of using map() on arrays, I more often use an operation that returns a dictionary from an array. A common case is fetching an array of data, then creating a local cache of it indexed by ID.

Is there a name for this operation? Is this something that others would like to see added to the standard library?

-Kenny

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Craig Cruden) #9

There is no equivalent to something like

array.zipWithIndex.toMap (or in this case array.zipWithIndex.toDictionary // where zipWithIndex creates tuples with the index - a specialized case of zip for Arrays with indexes.

···

On 2016-01-11, at 2:41:59, Ross O'Brien via swift-evolution <swift-evolution@swift.org> wrote:

Or an enumeration followed by a forEach.
["John", "Mike", "Amy", Kavin"].enumerate().forEach {
    dic[$0] = $1
}
That said, it requires creating a dictionary var first, not a let. If there was an initialiser for Dictionary which took an Array or EnumerateSequence, that might be useful. I'm not sure how I'd attempt to write such an initialiser though.

On Sun, Jan 10, 2016 at 7:08 PM, Donnacha Oisín Kidney <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I think that use of map is generally discouraged. forEach would probably be more explicit, or a for-loop.

On 10 Jan 2016, at 18:58, 肇鑫 via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

You can use dictionary in a map. You just ignore the return value of the map.

var dic = [Int:String]()
var index = 0

["John", "Mike", "Amy", "Kavin"].map {
    dic.updateValue($0, forKey: index)
    index += 1
}

print(dic) // [2: "Amy", 0: "John", 1: "Mike", 3: "Kavin"]

zhaoxin

On Mon, Jan 11, 2016 at 1:50 AM, Kenny Leung via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hi All.

I find that instead of using map() on arrays, I more often use an operation that returns a dictionary from an array. A common case is fetching an array of data, then creating a local cache of it indexed by ID.

Is there a name for this operation? Is this something that others would like to see added to the standard library?

-Kenny

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Kenny Leung) #10

I would like to keep this lightweight for the consumer, so you could write:

let people :[Person] = fetchPeople()
let cache :[Int:Person] = people.map {return $0.id}

-Kenny

···

On Jan 10, 2016, at 2:24 PM, Jo Albright via swift-evolution <swift-evolution@swift.org> wrote:

Possible solution to do what you are wanting.

extension Array {
    
    func map<T>(var d: [String:T] = [:], @noescape transform: (Int,Array.Generator.Element) throws -> [String:T]) rethrows -> [String:T] {
        
        for (i,item) in self.enumerate() {
            
            try d += transform(i,item)
            
        }
        
        return d
        
    }
    
}

func += <T>(inout lhs: [String:T], rhs: [String:T]) -> [String:T] {
    
    for (k,v) in rhs { lhs[k] = v }; return lhs
    
}

let names = ["Jo","Jenna","Jake","Julie"]
let ages = [32,20,46,39]
    
let namesInfo1 = names.map { ["\($0)": $1] }
namesInfo1 // ["2": "Jake", "1": "Jenna", "0": "Jo", "3": "Julie"]

let namesInfo2 = names.map(["6":"Jim"]) { ["\($0)": $1] }
namesInfo2 // ["2": "Jake", "1": "Jenna", "0": "Jo", "6": "Jim", "3": "Julie"]

let namesInfo3 = names.map { [$1: ages[$0]] }
namesInfo3 // ["Jenna": 20, "Jo": 32, "Jake": 46, "Julie": 39]

Designer . Developer .  Nerd
Jo Albright

On Jan 10, 2016, at 4:25 PM, Loïc Lecrenier via swift-evolution <swift-evolution@swift.org> wrote:

I think this is O(n^2) though, so it’s not really usable.
(It is destroying and copying the dictionary each time)

There really isn’t anything like map for dictionaries.
I am not convinced we should add it to the standard library though.

On Jan 10, 2016, at 10:19 PM, Ian Ynda-Hummel via swift-evolution <swift-evolution@swift.org> wrote:

I think this probably wants to be a `reduce`. Given the above example:

   ["John", "Mike", "Amy", "Kavin"].enumerate().reduce([Int: String]()) { (var dictionary, data) in
       dictionary[data.index] = data.element
       return dictionary
   }

Which means you create an immutable dictionary with `let`. This could probably look nicer, but I think it illustrates the idea, at least.

-Ian

On Sun, Jan 10, 2016 at 2:46 PM Craig Cruden via swift-evolution <swift-evolution@swift.org> wrote:
There is no equivalent to something like

array.zipWithIndex.toMap (or in this case array.zipWithIndex.toDictionary // where zipWithIndex creates tuples with the index - a specialized case of zip for Arrays with indexes.

On 2016-01-11, at 2:41:59, Ross O'Brien via swift-evolution <swift-evolution@swift.org> wrote:

Or an enumeration followed by a forEach.
["John", "Mike", "Amy", Kavin"].enumerate().forEach {
   dic[$0] = $1
}
That said, it requires creating a dictionary var first, not a let. If there was an initialiser for Dictionary which took an Array or EnumerateSequence, that might be useful. I'm not sure how I'd attempt to write such an initialiser though.

On Sun, Jan 10, 2016 at 7:08 PM, Donnacha Oisín Kidney <swift-evolution@swift.org> wrote:
I think that use of map is generally discouraged. forEach would probably be more explicit, or a for-loop.

On 10 Jan 2016, at 18:58, 肇鑫 via swift-evolution <swift-evolution@swift.org> wrote:

You can use dictionary in a map. You just ignore the return value of the map.

var dic = [Int:String]()
var index = 0

["John", "Mike", "Amy", "Kavin"].map {
   dic.updateValue($0, forKey: index)
   index += 1
}

print(dic) // [2: "Amy", 0: "John", 1: "Mike", 3: "Kavin"]

zhaoxin

On Mon, Jan 11, 2016 at 1:50 AM, Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:
Hi All.

I find that instead of using map() on arrays, I more often use an operation that returns a dictionary from an array. A common case is fetching an array of data, then creating a local cache of it indexed by ID.

Is there a name for this operation? Is this something that others would like to see added to the standard library?

-Kenny

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Thorsten Seitz) #11

struct Person {
    var id: Int
    var name: String
}
let tom = Person(id: 1, name: "Tom")
let dick = Person(id: 2, name: "Dick")
let harry = Person(id: 3, name: "Harry")
let people = [tom, dick, harry]

extension SequenceType {
    
    func toDict<Key: Hashable>(@noescape withKey extractKey: Self.Generator.Element -> Key)
  -> [Key:Self.Generator.Element]
    {
        return toDict { element in (extractKey(element), element) }
    }
    
    func toDict<Key: Hashable, Value>(@noescape mapping: Self.Generator.Element -> (Key, Value))
        -> [Key:Value]
    {
        var result: [Key:Value] = [:]
        for element in self {
            let (key, value) = mapping(element)
            result.updateValue(value, forKey: key)
        }
        return result
    }
}

let cache = people.toDict { $0.id }
cache

I named the method(s) „toDict“ instead of „map“ because map normally returns a collection which is either the same as the receiver or a simple one.
The second version is more general and allows to do things like

let dict = ["Tom", "Dick", "Harry"].enumerate().toDict { (index, value) in (index + 1, value) }

-Thorsten

···

Am 11.01.2016 um 17:56 schrieb Kenny Leung via swift-evolution <swift-evolution@swift.org>:

I would like to keep this lightweight for the consumer, so you could write:

let people :[Person] = fetchPeople()
let cache :[Int:Person] = people.map {return $0.id}

-Kenny

On Jan 10, 2016, at 2:24 PM, Jo Albright via swift-evolution <swift-evolution@swift.org> wrote:

Possible solution to do what you are wanting.

extension Array {

   func map<T>(var d: [String:T] = [:], @noescape transform: (Int,Array.Generator.Element) throws -> [String:T]) rethrows -> [String:T] {

       for (i,item) in self.enumerate() {

           try d += transform(i,item)

       }

       return d

   }

}

func += <T>(inout lhs: [String:T], rhs: [String:T]) -> [String:T] {

   for (k,v) in rhs { lhs[k] = v }; return lhs

}

let names = ["Jo","Jenna","Jake","Julie"]
let ages = [32,20,46,39]

let namesInfo1 = names.map { ["\($0)": $1] }
namesInfo1 // ["2": "Jake", "1": "Jenna", "0": "Jo", "3": "Julie"]

let namesInfo2 = names.map(["6":"Jim"]) { ["\($0)": $1] }
namesInfo2 // ["2": "Jake", "1": "Jenna", "0": "Jo", "6": "Jim", "3": "Julie"]

let namesInfo3 = names.map { [$1: ages[$0]] }
namesInfo3 // ["Jenna": 20, "Jo": 32, "Jake": 46, "Julie": 39]

Designer . Developer .  Nerd
Jo Albright

On Jan 10, 2016, at 4:25 PM, Loïc Lecrenier via swift-evolution <swift-evolution@swift.org> wrote:

I think this is O(n^2) though, so it’s not really usable.
(It is destroying and copying the dictionary each time)

There really isn’t anything like map for dictionaries.
I am not convinced we should add it to the standard library though.

On Jan 10, 2016, at 10:19 PM, Ian Ynda-Hummel via swift-evolution <swift-evolution@swift.org> wrote:

I think this probably wants to be a `reduce`. Given the above example:

  ["John", "Mike", "Amy", "Kavin"].enumerate().reduce([Int: String]()) { (var dictionary, data) in
      dictionary[data.index] = data.element
      return dictionary
  }

Which means you create an immutable dictionary with `let`. This could probably look nicer, but I think it illustrates the idea, at least.

-Ian

On Sun, Jan 10, 2016 at 2:46 PM Craig Cruden via swift-evolution <swift-evolution@swift.org> wrote:
There is no equivalent to something like

array.zipWithIndex.toMap (or in this case array.zipWithIndex.toDictionary // where zipWithIndex creates tuples with the index - a specialized case of zip for Arrays with indexes.

On 2016-01-11, at 2:41:59, Ross O'Brien via swift-evolution <swift-evolution@swift.org> wrote:

Or an enumeration followed by a forEach.
["John", "Mike", "Amy", Kavin"].enumerate().forEach {
  dic[$0] = $1
}
That said, it requires creating a dictionary var first, not a let. If there was an initialiser for Dictionary which took an Array or EnumerateSequence, that might be useful. I'm not sure how I'd attempt to write such an initialiser though.

On Sun, Jan 10, 2016 at 7:08 PM, Donnacha Oisín Kidney <swift-evolution@swift.org> wrote:
I think that use of map is generally discouraged. forEach would probably be more explicit, or a for-loop.

On 10 Jan 2016, at 18:58, 肇鑫 via swift-evolution <swift-evolution@swift.org> wrote:

You can use dictionary in a map. You just ignore the return value of the map.

var dic = [Int:String]()
var index = 0

["John", "Mike", "Amy", "Kavin"].map {
  dic.updateValue($0, forKey: index)
  index += 1
}

print(dic) // [2: "Amy", 0: "John", 1: "Mike", 3: "Kavin"]

zhaoxin

On Mon, Jan 11, 2016 at 1:50 AM, Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:
Hi All.

I find that instead of using map() on arrays, I more often use an operation that returns a dictionary from an array. A common case is fetching an array of data, then creating a local cache of it indexed by ID.

Is there a name for this operation? Is this something that others would like to see added to the standard library?

-Kenny

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Craig Cruden) #12

I named the method(s) „toDict“ instead of „map“ because map normally returns a collection which is either the same as the receiver or a simple one.
The second version is more general and allows to do things like

let dict = ["Tom", "Dick", "Harry"].enumerate().toDict { (index, value) in (index + 1, value) }

Map would probably be a more correct mathematically speaking — but it would be inconsistent with the naming convention already chosen for Swift. So for Swift - toDict (or toDictionary) would be the best choice.


(Kenny Leung) #13

Hmm…

Now that I look seriously at it, I have no idea how the first function works! Back to the books…

-Kenny

···

On Jan 12, 2016, at 10:11 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

struct Person {
    var id: Int
    var name: String
}
let tom = Person(id: 1, name: "Tom")
let dick = Person(id: 2, name: "Dick")
let harry = Person(id: 3, name: "Harry")
let people = [tom, dick, harry]

extension SequenceType {
    
    func toDict<Key: Hashable>(@noescape withKey extractKey: Self.Generator.Element -> Key)
  -> [Key:Self.Generator.Element]
    {
        return toDict { element in (extractKey(element), element) }
    }
    
    func toDict<Key: Hashable, Value>(@noescape mapping: Self.Generator.Element -> (Key, Value))
        -> [Key:Value]
    {
        var result: [Key:Value] = [:]
        for element in self {
            let (key, value) = mapping(element)
            result.updateValue(value, forKey: key)
        }
        return result
    }
}

let cache = people.toDict { $0.id }
cache

I named the method(s) „toDict“ instead of „map“ because map normally returns a collection which is either the same as the receiver or a simple one.
The second version is more general and allows to do things like

let dict = ["Tom", "Dick", "Harry"].enumerate().toDict { (index, value) in (index + 1, value) }

-Thorsten

Am 11.01.2016 um 17:56 schrieb Kenny Leung via swift-evolution <swift-evolution@swift.org>:

I would like to keep this lightweight for the consumer, so you could write:

let people :[Person] = fetchPeople()
let cache :[Int:Person] = people.map {return $0.id}

-Kenny

On Jan 10, 2016, at 2:24 PM, Jo Albright via swift-evolution <swift-evolution@swift.org> wrote:

Possible solution to do what you are wanting.

extension Array {

   func map<T>(var d: [String:T] = [:], @noescape transform: (Int,Array.Generator.Element) throws -> [String:T]) rethrows -> [String:T] {

       for (i,item) in self.enumerate() {

           try d += transform(i,item)

       }

       return d

   }

}

func += <T>(inout lhs: [String:T], rhs: [String:T]) -> [String:T] {

   for (k,v) in rhs { lhs[k] = v }; return lhs

}

let names = ["Jo","Jenna","Jake","Julie"]
let ages = [32,20,46,39]

let namesInfo1 = names.map { ["\($0)": $1] }
namesInfo1 // ["2": "Jake", "1": "Jenna", "0": "Jo", "3": "Julie"]

let namesInfo2 = names.map(["6":"Jim"]) { ["\($0)": $1] }
namesInfo2 // ["2": "Jake", "1": "Jenna", "0": "Jo", "6": "Jim", "3": "Julie"]

let namesInfo3 = names.map { [$1: ages[$0]] }
namesInfo3 // ["Jenna": 20, "Jo": 32, "Jake": 46, "Julie": 39]

Designer . Developer .  Nerd
Jo Albright

On Jan 10, 2016, at 4:25 PM, Loïc Lecrenier via swift-evolution <swift-evolution@swift.org> wrote:

I think this is O(n^2) though, so it’s not really usable.
(It is destroying and copying the dictionary each time)

There really isn’t anything like map for dictionaries.
I am not convinced we should add it to the standard library though.

On Jan 10, 2016, at 10:19 PM, Ian Ynda-Hummel via swift-evolution <swift-evolution@swift.org> wrote:

I think this probably wants to be a `reduce`. Given the above example:

  ["John", "Mike", "Amy", "Kavin"].enumerate().reduce([Int: String]()) { (var dictionary, data) in
      dictionary[data.index] = data.element
      return dictionary
  }

Which means you create an immutable dictionary with `let`. This could probably look nicer, but I think it illustrates the idea, at least.

-Ian

On Sun, Jan 10, 2016 at 2:46 PM Craig Cruden via swift-evolution <swift-evolution@swift.org> wrote:
There is no equivalent to something like

array.zipWithIndex.toMap (or in this case array.zipWithIndex.toDictionary // where zipWithIndex creates tuples with the index - a specialized case of zip for Arrays with indexes.

On 2016-01-11, at 2:41:59, Ross O'Brien via swift-evolution <swift-evolution@swift.org> wrote:

Or an enumeration followed by a forEach.
["John", "Mike", "Amy", Kavin"].enumerate().forEach {
  dic[$0] = $1
}
That said, it requires creating a dictionary var first, not a let. If there was an initialiser for Dictionary which took an Array or EnumerateSequence, that might be useful. I'm not sure how I'd attempt to write such an initialiser though.

On Sun, Jan 10, 2016 at 7:08 PM, Donnacha Oisín Kidney <swift-evolution@swift.org> wrote:
I think that use of map is generally discouraged. forEach would probably be more explicit, or a for-loop.

On 10 Jan 2016, at 18:58, 肇鑫 via swift-evolution <swift-evolution@swift.org> wrote:

You can use dictionary in a map. You just ignore the return value of the map.

var dic = [Int:String]()
var index = 0

["John", "Mike", "Amy", "Kavin"].map {
  dic.updateValue($0, forKey: index)
  index += 1
}

print(dic) // [2: "Amy", 0: "John", 1: "Mike", 3: "Kavin"]

zhaoxin

On Mon, Jan 11, 2016 at 1:50 AM, Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:
Hi All.

I find that instead of using map() on arrays, I more often use an operation that returns a dictionary from an array. A common case is fetching an array of data, then creating a local cache of it indexed by ID.

Is there a name for this operation? Is this something that others would like to see added to the standard library?

-Kenny

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--

Owen Zhao
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Kenny Leung) #14

This solution looks great! How do you feel about “mapDict”?

-Kenny

···

On Jan 12, 2016, at 10:28 AM, Craig Cruden <ccruden@novafore.com> wrote:

I named the method(s) „toDict“ instead of „map“ because map normally returns a collection which is either the same as the receiver or a simple one.
The second version is more general and allows to do things like

let dict = ["Tom", "Dick", "Harry"].enumerate().toDict { (index, value) in (index + 1, value) }

Map would probably be a more correct mathematically speaking — but it would be inconsistent with the naming convention already chosen for Swift. So for Swift - toDict (or toDictionary) would be the best choice.


(Robert Widmann) #15

When we drew these up in Swiftz we called them `mapAssociate` and `mapAssociateLabel` after the combinators "associate" and "label" in other languages

https://github.com/typelift/Swiftz/blob/master/Swiftz/ArrayExt.swift#L491-L504

~Robert Widmann

2016/01/13 11:13、Kenny Leung via swift-evolution <swift-evolution@swift.org> のメッセージ:

···

This solution looks great! How do you feel about “mapDict”?

-Kenny

On Jan 12, 2016, at 10:28 AM, Craig Cruden <ccruden@novafore.com> wrote:

I named the method(s) „toDict“ instead of „map“ because map normally returns a collection which is either the same as the receiver or a simple one.
The second version is more general and allows to do things like

let dict = ["Tom", "Dick", "Harry"].enumerate().toDict { (index, value) in (index + 1, value) }

Map would probably be a more correct mathematically speaking — but it would be inconsistent with the naming convention already chosen for Swift. So for Swift - toDict (or toDictionary) would be the best choice.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Thorsten Seitz) #16

I'd prefer "mapToDict" otherwise it sounds like a dictionary gets mapped, at least for me.

-Thorsten

···

Am 13.01.2016 um 17:13 schrieb Kenny Leung via swift-evolution <swift-evolution@swift.org>:

This solution looks great! How do you feel about “mapDict”?

-Kenny

On Jan 12, 2016, at 10:28 AM, Craig Cruden <ccruden@novafore.com> wrote:

I named the method(s) „toDict“ instead of „map“ because map normally returns a collection which is either the same as the receiver or a simple one.
The second version is more general and allows to do things like

let dict = ["Tom", "Dick", "Harry"].enumerate().toDict { (index, value) in (index + 1, value) }

Map would probably be a more correct mathematically speaking — but it would be inconsistent with the naming convention already chosen for Swift. So for Swift - toDict (or toDictionary) would be the best choice.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


#17

Doesn’t Swift prefer initializers?

So let’s build a Dictionary initializer that eats any sequence of (key, value) pairs:

extension Dictionary {
    init<S: SequenceType where S.Generator.Element == (Key, Value)>(keyValueSequence s: S) {
        self.init()
        for (key, value) in s {
            self[key] = value
        }
    }
}

do {
    // From array of (key, value) pairs
    let input = [("foo", 1), ("bar", 2)]
    let d = Dictionary(keyValueSequence: input)
    print(d)
}
do {
    // From another dictionary
    let input = [1: "foo", 2: "bar"]
    let d = Dictionary(keyValueSequence: input)
    print(d)
}
do {
    // Reverse key and values
    let input = [1: "foo", 2: "bar"]
    let d = Dictionary(keyValueSequence: input.map { ($1, $0) })
    print(d)
}

Gwendal

···

Le 13 janv. 2016 à 18:41, Thorsten Seitz via swift-evolution <swift-evolution@swift.org> a écrit :

I'd prefer "mapToDict" otherwise it sounds like a dictionary gets mapped, at least for me.

-Thorsten

Am 13.01.2016 um 17:13 schrieb Kenny Leung via swift-evolution <swift-evolution@swift.org>:

This solution looks great! How do you feel about “mapDict”?

-Kenny

On Jan 12, 2016, at 10:28 AM, Craig Cruden <ccruden@novafore.com> wrote:

I named the method(s) „toDict“ instead of „map“ because map normally returns a collection which is either the same as the receiver or a simple one.
The second version is more general and allows to do things like

let dict = ["Tom", "Dick", "Harry"].enumerate().toDict { (index, value) in (index + 1, value) }

Map would probably be a more correct mathematically speaking — but it would be inconsistent with the naming convention already chosen for Swift. So for Swift - toDict (or toDictionary) would be the best choice.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Nate Cook) #18

A brief draft is below... I had mostly written this up before I saw the thread and Gwendal's similar contribution -- happy to hear feedback and fold in comments/revisions!

Nate

···

---

Introduction

The Dictionary type should allow initialization from a sequence of (Key, Value) tuples.

Motivation

Array and Set both have initializers that create a new instance from a sequence of elements. The Array initializer is useful for converting other sequences and collections to the "standard" collection type, but the Set initializer is essential for recovering set operations after performing any functional operations on a set. For example, filtering a set produces a collection without any kind of set operations available:

let numberSet = Set(1 ... 100)
let fivesOnly = numberSet.lazy.filter { $0 % 5 == 0 }

"fivesOnly" is a LazyFilterCollection<Set<Int>> instead of a Set -- sending that back through the Set sequence initializer restores the expected methods:

let fivesOnlySet = Set(numberSet.lazy.filter { $0 % 5 == 0 })
fivesOnlySet.isSubsetOf(numberSet) // true

Dictionary, on the other hand, has no such initializer, so a similar operation leaves no room except for building a mutable Dictionary via iteration or functional methods with dubious performance. These techniques also don't support type inference from the source sequence, increasing verbosity:

var viaIteration: [String: Int] = [:]
for (key, value) in evenOnly {
    viaIteration[key] = value
}

let viaFunction: [String: Int] = evenOnly.reduce([:]) { (cumulative, keyValue) in
    var mutableDictionary = cumulative
    mutableDictionary[keyValue.0] = keyValue.1
    return mutableDictionary
}

Proposed solution

The proposed solution would add an initializer to Dictionary that accepts any sequence of (Key, Value) tuple pairs, matching the Dictionary's element type when treated as a sequence:

init<S: SequenceType where S.Generator.Element == Generator.Element>(_ sequence: S)

Instead of the techniques for recovering a Dictionary shown above, the proposed initializer would allow a much cleaner syntax to be written:

let viaProposed = Dictionary(evenOnly)

Moreover, this new initializer would allow for some convenient uses that aren't currently possible.

:+1:t3: Initializing from an array of tuples:

let dictFromArray = Dictionary([("a", 1), ("b", 2), ("c", 3), ("d", 4)])

:clap:t3: Initializing from a DictionaryLiteral (the type, not an actual literal):

let literal: DictionaryLiteral = ["a": 1, "b": 2, "c": 3, "d": 4]
let dictFromDL = Dictionary(literal)

:tada: Initializing from a pair of zipped sequences (examples abound):

let letters = "abcdefghij".characters.lazy.map { String($0) }
let dictFromZip = Dictionary(zip(letters, 1...10))
// ["b": 2, "a": 1, "i": 9, "j": 10, "c": 3, "e": 5, "f": 6, "g": 7, "d": 4, "h": 8]

Potential pitfalls

One caveat is that the new initializer doesn't prevent using a sequence with multiple identical keys. In such a case, the last key/value would "win" and exist in the dictionary. Such an initialization is a compile-time error with a dictionary literal, but succeeds under the new initializer:

let _ = ["z": 1, "z": 2, "z": 3, "z": 4]
// fatal error: Dictionary literal contains duplicate keys
Dictionary([("z", 1), ("z", 2), ("z", 3), ("z", 4)])
// ["z": 4]

This behavior is particularly troublesome when used in conjunction with a mapping operation that modifies a dictionary's keys, since dictionaries have no particular guaranteed order:

let overlapping = Dictionary(dictFromArray.lazy.map { (_, value) in ("z", value) })
// ["z": ???]

While a pitfall, this behavior is less a symptom of the proposed API and more an inherent problem with recovering a dictionary after modifying its keys. The current ways of rebuilding a dictionary (as shown above) are just as susceptible to silently dropping values. Moreover, the sequence-based initializer for Set exhibits the same behavior, though slightly less problematic in most cases:

let dividedNumbers = Set(numberSet.map { $0 / 20 })
// {4, 5, 2, 0, 1, 3}

Given the potential lossiness of the initializer, should it use a parameter name for the sequence? I would suggest not, to match the syntax of Array.init(_:slight_smile: and Set.init(_:), but a parameter like "collapsingKeys" would make the risk clear to users.

Detailed design

The implementation is simple enough to show in the proposal:

extension Dictionary {
    /// Creates a dictionary with the keys and values in the given sequence.
    init<S: SequenceType where S.Generator.Element == Generator.Element>(_ sequence: S) {
        self.init()
        for (key, value) in sequence {
            updateValue(value, forKey: key)
        }
    }
}

(As part of the standard library, this could use the nativeUpdateValue method.)

Impact on existing code

As a new API, this will have no impact on existing code.

Alternatives considered

As suggested in the thread below, a method could be added to SequenceType that would build a dictionary. This approach seems less of a piece with the rest of the standard library, and overly verbose when used with a Dictionary that is only passing through filtering or mapping operations. I don't think the current protocol extension system could handle a passthrough case (i.e., something like "extension SequenceType where Generator.Element == (Key, Value)").

Alternately, the status quo could be maintained. Which would be sad.

On Jan 13, 2016, at 11:55 AM, Gwendal Roué via swift-evolution <swift-evolution@swift.org> wrote:

Doesn’t Swift prefer initializers?

So let’s build a Dictionary initializer that eats any sequence of (key, value) pairs:

extension Dictionary {
    init<S: SequenceType where S.Generator.Element == (Key, Value)>(keyValueSequence s: S) {
        self.init()
        for (key, value) in s {
            self[key] = value
        }
    }
}

do {
    // From array of (key, value) pairs
    let input = [("foo", 1), ("bar", 2)]
    let d = Dictionary(keyValueSequence: input)
    print(d)
}
do {
    // From another dictionary
    let input = [1: "foo", 2: "bar"]
    let d = Dictionary(keyValueSequence: input)
    print(d)
}
do {
    // Reverse key and values
    let input = [1: "foo", 2: "bar"]
    let d = Dictionary(keyValueSequence: input.map { ($1, $0) })
    print(d)
}

Gwendal

Le 13 janv. 2016 à 18:41, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

I'd prefer "mapToDict" otherwise it sounds like a dictionary gets mapped, at least for me.

-Thorsten

Am 13.01.2016 um 17:13 schrieb Kenny Leung via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

This solution looks great! How do you feel about “mapDict”?

-Kenny

On Jan 12, 2016, at 10:28 AM, Craig Cruden <ccruden@novafore.com <mailto:ccruden@novafore.com>> wrote:

I named the method(s) „toDict“ instead of „map“ because map normally returns a collection which is either the same as the receiver or a simple one.
The second version is more general and allows to do things like

let dict = ["Tom", "Dick", "Harry"].enumerate().toDict { (index, value) in (index + 1, value) }

Map would probably be a more correct mathematically speaking — but it would be inconsistent with the naming convention already chosen for Swift. So for Swift - toDict (or toDictionary) would be the best choice.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Brent Royal-Gordon) #19

One caveat is that the new initializer doesn't prevent using a sequence with multiple identical keys. In such a case, the last key/value would "win" and exist in the dictionary.

Another alternative would be to make the initializer failable and have it fail if a key is duplicated.

···

--
Brent Royal-Gordon
Architechies


(David Hart) #20

It may sound counter-intuitive to have such an initialiser failable for many users. I *think* I would prefer it to silently use the last key.

···

On 15 Jan 2016, at 01:31, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

One caveat is that the new initializer doesn't prevent using a sequence with multiple identical keys. In such a case, the last key/value would "win" and exist in the dictionary.

Another alternative would be to make the initializer failable and have it fail if a key is duplicated.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution