# Map vs list comprehension

**URL:** https://discourse.julialang.org/t/map-vs-list-comprehension/916
**Category:** General Usage
**Created:** [December 13, 2016, 12:50pm UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916 "2016-12-13T12:50:07Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![mzaffalon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mzaffalon/32/214168_2.png) [@mzaffalon](https://discourse.julialang.org/u/mzaffalon)
#### Post date: [December 13, 2016, 12:50pm UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/1 "2016-12-13T12:50:07Z")

</div>

What is the difference between `map(v -> f(v), lst)` and `[f(v) for v in lst]`?  
I have seen [this discussion](https://groups.google.com/d/msg/julia-users/QMEvSThtXGI/RJlKuIsThl8J) but the focus was on speed and memory allocation.

---

<div class="post-metadata">

### Author: ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)
#### Post date: [December 13, 2016, 2:11pm UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/2 "2016-12-13T14:11:47Z")

</div>

Conceptually, there is no difference. Note that you can simply write

```julia
map(f, lst)

```

if `f` is a previously-defined function.

---

<div class="post-metadata">

### Author: ![mzaffalon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mzaffalon/32/214168_2.png) [@mzaffalon](https://discourse.julialang.org/u/mzaffalon)
#### Post date: [December 13, 2016, 2:31pm UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/3 "2016-12-13T14:31:01Z")

</div>

Why are there two versions?

---

<div class="post-metadata">

### Author: ![dfdx](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dfdx/32/120_2.png) [@dfdx](https://discourse.julialang.org/u/dfdx)
#### Post date: [December 13, 2016, 2:39pm UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/4 "2016-12-13T14:39:08Z")

</div>

They are not quite the same. For example, with list comprehension you can additionally filter elements:

```
[x for x in 1:10 if x % 2 == 0]

```

But `map` may be shorter and more convenient, e.g.:

```
[f(input) for input in inputs]
map(f, inputs)

```

In addition, `map` (mostly) preserves type of a collection, while list comprehencion doesn’t. Compare:

```
map(x -> x + 1, Set([1, 2, 3]))
[x + 1 for x in Set([1, 2, 3])]

```

---

<div class="post-metadata">

### Author: ![mzaffalon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mzaffalon/32/214168_2.png) [@mzaffalon](https://discourse.julialang.org/u/mzaffalon)
#### Post date: [December 23, 2016, 6:42am UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/5 "2016-12-23T06:42:28Z")

</div>

I still having a hard time with all this (Julia v0.5).

Comprehension on an `Array{Tuple}` is fine

```julia
julia> a=[(1,2),(3,4)];
julia> [x for (x,y) in a]
2-element Array{Int64,1}:

```

but not `map`

```julia
julia> map((x,y)->x, a)
ERROR: MethodError: no method matching (::##3#4)(::Tuple{Int64,Int64})

```

even though

```julia
(x,y) = a[1]

```

is fine.

Also `filter` raises an error on

```julia
julia> filter((x,y)->x==3, a)
ERROR: MethodError: no method matching (::##5#6)(::Tuple{Int64,Int64})

```

because `a` is not an associative collection (two arguments are passed to the function in this case: this is specified in the manual). Indeed `filter` works here

```julia
julia> filter((x,y)->x==3, Dict(a))
Dict{Int64,Int64} with 1 entry:

```

Then again neither one is valid:

```julia
julia> foreach((x,y)->println(x), a)
ERROR: MethodError: no method matching (::##9#10)(::Pair{Int64,Int64})
julia> foreach((x,y)->println(x), Dict(a))
ERROR: MethodError: no method matching (::##11#12)(::Pair{Int64,Int64})

```

Instead

```julia
julia> for (x,y) in a
       println(x)
       end

```

is OK.

Then I come across this:

```julia
julia> filter((x,y)->begin println(typeof(x)); x[1]==3; end, Dict(a))
Int64
Int64
Dict{Int64,Int64} with 1 entry:

```

but it should be an error because `Int64` has no `getindex`.

I am very confused, but there must have been a good reason to have it this way and I cannot see it. How can I picture all this in a more systematic way?

(And all this because of [this post](https://discourse.julialang.org/t/pair-a-b-vs-tuple-a-b/942).)

---

<div class="post-metadata">

### Author: ![mzaffalon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mzaffalon/32/214168_2.png) [@mzaffalon](https://discourse.julialang.org/u/mzaffalon)
#### Post date: [December 23, 2016, 9:29am UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/6 "2016-12-23T09:29:55Z")

</div>

> [@mzaffalon](#):
>
> but it should be an error because Int64 has no getindex.

```julia
julia> a = Int64(6); a[1]
6

```

Rather unexpected…

---

<div class="post-metadata">

### Author: ![Evizero](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evizero/32/10118_2.png) [@Evizero](https://discourse.julialang.org/u/Evizero)
#### Post date: [December 23, 2016, 12:23pm UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/7 "2016-12-23T12:23:54Z")

</div>

I suspect (but don’t actually know) that one reason for `Int64` to provide a `getindex` implementation is to make `broadcast` work in a general way.

---

<div class="post-metadata">

### Author: ![pfitzseb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pfitzseb/32/45566_2.png) [@pfitzseb](https://discourse.julialang.org/u/pfitzseb)
#### Post date: [December 23, 2016, 12:32pm UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/8 "2016-12-23T12:32:39Z")

</div>

The key difference between loops/comprehensions and the anonymous functions used in `filter`, `map` etc. seems to be the implicit tuple destructuring that only happens in the former case (which makes sense for dispatch).

Imho the outlier here is `filter` for associative iterables, also see  
[https://github.com/JuliaLang/julia/issues/17886](https://github.com/JuliaLang/julia/issues/17886)

So apart from that, the system appears to be consistent: In loops, comprehensions and assignments you get automatic tuple destructuring if you want it, and otherwise you don’t.

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [December 23, 2016, 3:04pm UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/9 "2016-12-23T15:04:00Z")

</div>

> [@Evizero](#):
>
> I suspect (but don’t actually know) that one reason for Int64 to provide a getindex implementation is to make broadcast work in a general way.

No, `broadcast` doesn’t need this (in 0.6, it works on arbitrary “scalar” types that don’t have `getindex`).

I think that largely this is the Matlab legacy; in Matlab, numbers are “really” 1x1 matrices internally, and it is quite common to write functions that are supposed to work on either scalars or arrays of numbers in order to vectorize. To simplify the process of writing such generic scalar/vector code, you can access numbers as if they were 0-dimensional arrays in Julia.

I think that a lot of the need for this should be gone now with 0.5’s dot-call syntax: in the cases where you would previously have written a generic vector/scalar function, you should now just write the scalar function `f(x)`, and then apply it to arrays `A` with `f.(A)`. This is not only easier, it is also faster because it can fuse with other elementwise operations and the result can be assigned in-place with `.=`.

See also: [make numbers non-iterable? · Issue #7903 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/7903)

---

<div class="post-metadata">

### Author: ![mzaffalon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mzaffalon/32/214168_2.png) [@mzaffalon](https://discourse.julialang.org/u/mzaffalon)
#### Post date: [December 24, 2016, 7:07am UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/10 "2016-12-24T07:07:14Z")

</div>

Oh, nice explanation, thank you. The implicit tuple destructuring is the bit I was missing.

---

<div class="post-metadata">

### Author: ![Nosferican](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nosferican/32/9275_2.png) [@Nosferican](https://discourse.julialang.org/u/Nosferican)
#### Post date: [June 18, 2017, 7:30pm UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/11 "2017-06-18T19:30:31Z")

</div>

> [@mzaffalon](#):
>
> map((x,y)-\>x, a)

Should be:

```julia
map((elem) -> elem[1], object)

```

since the elements of the object are tuples and you want to select the first element of the tuple.

---

<div class="post-metadata">

### Author: ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)
#### Post date: [June 18, 2017, 7:48pm UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/12 "2017-06-18T19:48:14Z")

</div>

Note that there is a function `first`:

```julia
julia 0.6> first((1,2))
1

```

So you can just write

```julia
julia 0.6> a = [(1, 2), (3, 4)]
2-element Array{Tuple{Int64,Int64},1}:
 (1, 2)
 (3, 4)

julia 0.6> first.(a)
2-element Array{Int64,1}:
 1
 3

```

---

<div class="post-metadata">

### Author: ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)
#### Post date: [June 30, 2017, 9:01am UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/13 "2017-06-30T09:01:15Z")

</div>

> [@dfdx](#):
>
> In addition, `map` (mostly) preserves type of a collection, while list comprehencion doesn’t. Compare:
> 
> ```
> map(x -> x + 1, Set([1, 2, 3]))
> [x + 1 for x in Set([1, 2, 3])]
> 
> ```

Is there a reason for this behavior?

---

<div class="post-metadata">

### Author: ![dfdx](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dfdx/32/120_2.png) [@dfdx](https://discourse.julialang.org/u/dfdx)
#### Post date: [June 30, 2017, 9:24am UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/14 "2017-06-30T09:24:10Z")

</div>

By definition, _list comprehension_ builds a _list_. You could possibly have a kind of “collection comprehension” that tries to preserve collection type. But I can see a little value for it and a number of hard design choices, e.g. what syntax this feature should have, how to do type dispatching (which is a solved issue for `map` in Julia), how to handle filtering in general collections (i.e. `[x for x in xs if condition(x)]` for lists), etc.

---

<div class="post-metadata">

### Author: ![Evizero](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evizero/32/10118_2.png) [@Evizero](https://discourse.julialang.org/u/Evizero)
#### Post date: [June 30, 2017, 9:29am UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/15 "2017-06-30T09:29:39Z")

</div>

> [@dfdx](#):
>
> By definition, list comprehension builds a list.

might make more sense to call it array comprehension then, since it understands shape.

```julia
julia> A = rand(2,3)
2×3 Array{Float64,2}:
 0.05249 0.251237 0.911031
 0.461673 0.73201 0.854654

julia> [a^2 for a in A]
2×3 Array{Float64,2}:
 0.0027552 0.0631202 0.829977
 0.213142 0.535838 0.730434

```

---

<div class="post-metadata">

### Author: ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)
#### Post date: [July 1, 2017, 2:08am UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/16 "2017-07-01T02:08:53Z")

</div>

We don’t call them list comprehensions nor do we call the data structure lists – that’s Python terminology. Julia’s random access n-dimensional data type is an array and the comprehensions that construct them are array comprehensions.

---

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [July 1, 2017, 3:28pm UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/17 "2017-07-01T15:28:37Z")

</div>

map does not preserve the type of an `Array` in v0.6.

Julia v0.6

```julia
julia> typeof(map(identity,Any[1,2,3]))
Array{Int64,1}

```

Julia v0.5

```julia
julia> typeof(map(identity,Any[1,2,3]))
Array{Any,1}

```

Operating on an `Array`, `map` in v0.6 appears to return an array of the least common (non-proper) supertype of the elements.

This is one of the thousand cuts `Symata.jl` has suffered under v0.6. (Not that I’m complaining, I knew the API was in flux.)

---

<div class="post-metadata">

### Author: ![ohsonice](https://avatars.discourse-cdn.com/v4/letter/o/d6d6ee/32.png) [@ohsonice](https://discourse.julialang.org/u/ohsonice)
#### Post date: [July 2, 2017, 10:03pm UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/18 "2017-07-02T22:03:57Z")

</div>

Would pre-allocation solve that problem? In that case, it is explicit that you are persevering type:

```julia
 x = Any[1,2,3]
 y = similar(x)
 map!(identity,y,x)

```

---

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [July 2, 2017, 11:21pm UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/19 "2017-07-02T23:21:32Z")

</div>

Yes, preallocation solves the problem, or my problem, at any rate. This was relatively easy to fix once I discovered the origin of the bad behavior.

---

<div class="post-metadata">

### Author: ![pint](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pint/32/125_2.png) [@pint](https://discourse.julialang.org/u/pint)
#### Post date: [July 3, 2017, 7:19am UTC](https://discourse.julialang.org/t/map-vs-list-comprehension/916/20 "2017-07-03T07:19:33Z")

</div>

how is that a bad behavior though? you want map to treat `identity` as special case?

[Next page](https://discourse.julialang.org/t/map-vs-list-comprehension/916.md?page=2)
