Why can I not filter or map a dictionary to another dictionary?


(Rick M) #1

It seems fairly natural to want to do this:

let bigDictionary = ...
let smallerDictionary = bigDictionary.filter { key, value in <some test returning Bool> }

Similarly, it seems natural to want to map this way.

Am I overlooking something?

···

--
Rick Mann
rmann@latencyzero.com


(Hooman Mehr) #2

The rational for returning Array is here: https://github.com/apple/swift/blob/master/docs/StdlibRationales.rst#high-order-functions-on-collections-return-arrays

I have this simple extension to dictionary:

extension Dictionary {
    
    mutating func append(_ element: Element) {

        self[element.key] = element.value
    }
    
    mutating func append<S: Sequence>(contentsOf sequence: S) where S.Iterator.Element == Element {
        
        for element in sequence { append(element) }
    }
    
    init<S: Sequence>(_ sequence: S) where S.Iterator.Element == Element {
        
        self.init()
        self.append(contentsOf: sequence)
    }
}

Which enables doing this:

var d = ["A":1, "B":2, "C": 3, "D": 4, "E": 5]

d.append((key: "F", value: 6))

d.append(contentsOf: ["G": 7, "H": 8])

var e = Dictionary(d.filter { $0.key < "E" })

print(e)

You should note that the meaning of `append` here is different from ordinary (array-like) collections.

···

On Oct 26, 2016, at 5:12 PM, Rick Mann via swift-users <swift-users@swift.org> wrote:

It seems fairly natural to want to do this:

let bigDictionary = ...
let smallerDictionary = bigDictionary.filter { key, value in <some test returning Bool> }

Similarly, it seems natural to want to map this way.

Am I overlooking something?

--
Rick Mann
rmann@latencyzero.com

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


(Dave Abrahams) #3

It's reasonable for filter, but maybe not for map. Map follows certain
laws, and one of them is that you get the same number of elements out as
you put in. But you can easily map all keys to the same key, and the
law would be violated.

···

on Wed Oct 26 2016, Rick Mann <swift-users-AT-swift.org> wrote:

It seems fairly natural to want to do this:

let bigDictionary = ...
let smallerDictionary = bigDictionary.filter { key, value in <some test returning Bool> }

Similarly, it seems natural to want to map this way.

--
-Dave


(Vince O'Sullivan) #4

You can. You just need to get the syntax right:

let smallerDictionary = bigDictionary.filter { (key, value) in <some test returning Bool> }

let bd = [1:"A", 2:"B", 3:"C"]
let sd = bd.filter{(k, v) in
    k > 1}
dump(sd)

···

On 27/10/2016, 01:12, "Rick Mann via swift-users" <swift-users-bounces@swift.org on behalf of swift-users@swift.org> wrote:

    It seems fairly natural to want to do this:
    
    let bigDictionary = ...
    let smallerDictionary = bigDictionary.filter { key, value in <some test returning Bool> }
    
    Similarly, it seems natural to want to map this way.
    
    Am I overlooking something?
    
    --
    Rick Mann
    rmann@latencyzero.com
    
    _______________________________________________
    swift-users mailing list
    swift-users@swift.org
    https://lists.swift.org/mailman/listinfo/swift-users


(Rick M) #5

Sure map would produce a dictionary of the same number of entries. I didn't mean to imply map would also filter. But I'm basically transforming a JSON dictionary into a new version of that dictionary with fewer elements. I'd like to first filter it, then map it, and have the result be a dictionary.

···

On Oct 26, 2016, at 22:23 , Dave Abrahams via swift-users <swift-users@swift.org> wrote:

on Wed Oct 26 2016, Rick Mann <swift-users-AT-swift.org> wrote:

It seems fairly natural to want to do this:

let bigDictionary = ...
let smallerDictionary = bigDictionary.filter { key, value in <some test returning Bool> }

Similarly, it seems natural to want to map this way.

It's reasonable for filter, but maybe not for map. Map follows certain
laws, and one of them is that you get the same number of elements out as
you put in. But you can easily map all keys to the same key, and the
law would be violated.

--
Rick Mann
rmann@latencyzero.com


(Vince O'Sullivan) #6

Ah. Having seen the other answers, I can now see the implied question.

···

On 27/10/2016, 07:39, "Vincent O'Sullivan via swift-users" <swift-users-bounces@swift.org on behalf of swift-users@swift.org> wrote:

    You can. You just need to get the syntax right:
    
    let smallerDictionary = bigDictionary.filter { (key, value) in <some test returning Bool> }
    
    let bd = [1:"A", 2:"B", 3:"C"]
    let sd = bd.filter{(k, v) in
        k > 1}
    dump(sd)
    
    On 27/10/2016, 01:12, "Rick Mann via swift-users" <swift-users-bounces@swift.org on behalf of swift-users@swift.org> wrote:
    
        It seems fairly natural to want to do this:
        
        let bigDictionary = ...
        let smallerDictionary = bigDictionary.filter { key, value in <some test returning Bool> }
        
        Similarly, it seems natural to want to map this way.
        
        Am I overlooking something?
        
        --
        Rick Mann
        rmann@latencyzero.com
        
        _______________________________________________
        swift-users mailing list
        swift-users@swift.org
        https://lists.swift.org/mailman/listinfo/swift-users
        
    _______________________________________________
    swift-users mailing list
    swift-users@swift.org
    https://lists.swift.org/mailman/listinfo/swift-users


(Rick M) #7

Ah. Having seen the other answers, I can now see the implied question.

   You can. You just need to get the syntax right:

   let smallerDictionary = bigDictionary.filter { (key, value) in <some test returning Bool> }

   let bd = [1:"A", 2:"B", 3:"C"]
   let sd = bd.filter{(k, v) in
       k > 1}
   dump(sd)

In this example, sd is an array of tuples of (key, value), not a dictionary.

···

On Oct 26, 2016, at 23:43 , Vincent O'Sullivan via swift-users <swift-users@swift.org> wrote:
On 27/10/2016, 07:39, "Vincent O'Sullivan via swift-users" <swift-users-bounces@swift.org on behalf of swift-users@swift.org> wrote:

   On 27/10/2016, 01:12, "Rick Mann via swift-users" <swift-users-bounces@swift.org on behalf of swift-users@swift.org> wrote:

       It seems fairly natural to want to do this:

       let bigDictionary = ...
       let smallerDictionary = bigDictionary.filter { key, value in <some test returning Bool> }

       Similarly, it seems natural to want to map this way.

       Am I overlooking something?

       --
       Rick Mann
       rmann@latencyzero.com

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

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

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

--
Rick Mann
rmann@latencyzero.com


(Dave Abrahams) #8

It seems fairly natural to want to do this:

let bigDictionary = ...
let smallerDictionary = bigDictionary.filter { key, value in <some test returning Bool> }

Similarly, it seems natural to want to map this way.

It's reasonable for filter, but maybe not for map. Map follows certain
laws, and one of them is that you get the same number of elements out as
you put in. But you can easily map all keys to the same key, and the
law would be violated.

Sure map would produce a dictionary of the same number of entries. I
didn't mean to imply map would also filter.

I think you're missing my point. What result do you expect from

  {1:2, 3:4}.map { _ in (1, 1) }

? How many elements does it have? Note that you can't have the same key
twice in a Dictionary.

But I'm basically transforming a JSON dictionary into a new version of
that dictionary with fewer elements. I'd like to first filter it, then
map it, and have the result be a dictionary.

What we need are Dictionary initializers that operate on Sequences, per
https://github.com/apple/swift-evolution/blob/master/proposals/0100-add-sequence-based-init-and-merge-to-dictionary.md

    Dictionary(merging: d.lazy.filter {... }.map {...})

That would get you the result you're looking for in a principled way,
without creating an intermediate Array.

···

on Thu Oct 27 2016, Rick Mann <rmann-AT-latencyzero.com> wrote:

On Oct 26, 2016, at 22:23 , Dave Abrahams via swift-users <swift-users@swift.org> wrote:
on Wed Oct 26 2016, Rick Mann <swift-users-AT-swift.org> wrote:

--
-Dave


(Rick M) #9

It seems fairly natural to want to do this:

let bigDictionary = ...
let smallerDictionary = bigDictionary.filter { key, value in <some test returning Bool> }

Similarly, it seems natural to want to map this way.

It's reasonable for filter, but maybe not for map. Map follows certain
laws, and one of them is that you get the same number of elements out as
you put in. But you can easily map all keys to the same key, and the
law would be violated.

Sure map would produce a dictionary of the same number of entries. I
didn't mean to imply map would also filter.

I think you're missing my point. What result do you expect from

{1:2, 3:4}.map { _ in (1, 1) }

Fair point. I suppose I'd be okay with unpredictable results, or an exception, if possible.

? How many elements does it have? Note that you can't have the same key
twice in a Dictionary.

But I'm basically transforming a JSON dictionary into a new version of
that dictionary with fewer elements. I'd like to first filter it, then
map it, and have the result be a dictionary.

What we need are Dictionary initializers that operate on Sequences, per
https://github.com/apple/swift-evolution/blob/master/proposals/0100-add-sequence-based-init-and-merge-to-dictionary.md

   Dictionary(merging: d.lazy.filter {... }.map {...})

That would get you the result you're looking for in a principled way,
without creating an intermediate Array.

I guess for now I write it in a clunky way.

···

On Oct 27, 2016, at 10:29 , Dave Abrahams <dabrahams@apple.com> wrote:
on Thu Oct 27 2016, Rick Mann <rmann-AT-latencyzero.com> wrote:

On Oct 26, 2016, at 22:23 , Dave Abrahams via swift-users <swift-users@swift.org> wrote:
on Wed Oct 26 2016, Rick Mann <swift-users-AT-swift.org> wrote:

--
Rick Mann
rmann@latencyzero.com