# Can I get this syntax to work using zip?

**URL:** <https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009>\
**Category:** General Usage\
**Tags:** tuple\
**Created:** [September 10, 2021, 9:14pm UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009 "2021-09-10T21:14:48Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [September 10, 2021, 9:14pm UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/1 "2021-09-10T21:14:49Z")

</div>

Hello!

Suppose I have two points defined as:

```julia
p1 = (1.0,1.0)
p2 = (1.0,1.025)

```

Then I want to calculate the pair-wise distance between the two as such:

```julia
for (i,j) in zip(p1,p2)
    diff = i - j
end

```

And I want the output to be a tuple the same size as p1 and p2, with in this case values of:

```julia
(0.0,0.025)

```

I am aware this simple example can be done using `.`. I am specificially asking if this could work as I want using zip 🙂

Kind regards

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [September 10, 2021, 9:24pm UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/2 "2021-09-10T21:24:19Z")

</div>

The obvious way to write it with `zip` doesn’t in fact return a tuple, because `zip` doesn’t. You could fix it by defining your own one. Or by just using the fact that `map` works like `zip` on multiple arguments:

```julia
julia> map(zip((1.0, 2.0), (3.0, 5.0))) do (i,j)
         diff = i - j
       end
2-element Vector{Float64}:
 -2.0
 -3.0

julia> _zip(ts::Tuple...) = ntuple(i -> map(t -> t[i], ts), minimum(length, ts));

julia> map(_zip((1.0, 2.0), (3.0, 5.0))) do (i,j)
          i - j # diff
       end
(-2.0, -3.0)

julia> map((1.0, 2.0), (3.0, 5.0)) do i,j
         i - j
       end
(-2.0, -3.0)

```

---

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [September 10, 2021, 9:35pm UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/3 "2021-09-10T21:35:58Z")

</div>

Thanks, that works for me! It is perhaps better to just use map in this case, yes 🙂

I have one question though, which is pretty basic, how would I assign the end result of map to something? Like I would usually do for a = 1 etc., I can’t seem to get it to work when using map.

If I put what you have wirtten in a function though it spits out what I want:

```julia
function pairwise_dist(p1,p2)
    map(p1,p2) do i,j
        diff = i - j
    end
    
end

```

So I am just asking to learn

Kind regards

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [September 10, 2021, 9:39pm UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/4 "2021-09-10T21:39:51Z")

</div>

Writing `diff = i - j` inside the function body here is just a note to yourself, probably not best practice. To assign what the whole `map` expression returns, you need `a = map(...)` even if there’s a `do` involved. (Every expression in Julia returns something, so you will also see things like `b = if x<0 ... else ... end`.)

---

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [September 10, 2021, 10:11pm UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/5 "2021-09-10T22:11:06Z")

</div>

I renamed diff to d and I see, it worked - thanks!

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [September 10, 2021, 11:20pm UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/6 "2021-09-10T23:20:29Z")

</div>

The following looks nice too:

```julia
dif = Tuple(i-j for (i,j) in zip(p1,p2))

```

---

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [September 11, 2021, 8:06am UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/7 "2021-09-11T08:06:05Z")

</div>

> [@rafael.guerra](#):
>
> `Tuple(i-j for (i,j) in zip(p1,p2))`

Thanks! map was more performant for me, so will stick to that, but that shows it is possible.

Kind regards

---

<div class="post-metadata">

**Author:** ![genkuroki](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/genkuroki/32/18030_2.png) [@genkuroki](https://discourse.julialang.org/u/genkuroki)\
**Post date:** [September 11, 2021, 8:31am UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/8 "2021-09-11T08:31:13Z")

</div>

Input:

```julia
a = (1.0, 2.0)
b = (3.0, 5.0)
b .- a

```

Output:

```julia
(2.0, 3.0)

```

Input:

```julia
using BenchmarkTools
@btime $(Ref(b))[] .- $(Ref(a))[]

```

Output:

```julia
  1.400 ns (0 allocations: 0 bytes)
(2.0, 3.0)

```

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [September 11, 2021, 8:37am UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/9 "2021-09-11T08:37:22Z")

</div>

Note OP’s premise:

> [@Ahmed\_Salih](#):
>
> I am aware this simple example can be done using `.`

---

<div class="post-metadata">

**Author:** ![genkuroki](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/genkuroki/32/18030_2.png) [@genkuroki](https://discourse.julialang.org/u/genkuroki)\
**Post date:** [September 11, 2021, 9:29am UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/10 "2021-09-11T09:29:11Z")

</div>

I’m sorry for missing it.

We can type-stably create a tuple using `map` and `zip` by doing the following, but it will be less efficient because it goes through a `Vector`.

```julia
using BenchmarkTools

f(a::NTuple{N}, b::NTuple{N}) where N =
    NTuple{N}(map(((i, j),) -> j - i, zip(a, b)))

a = (1.0, 2.0)
b = (3.0, 5.0)
@btime f($a, $b)

```

Output:

```julia
 30.885 ns (1 allocation: 96 bytes)
(2.0, 3.0)

```

The following similar code using `zip` is more efficient (but too complex than `b .- a`).

```julia
g(a::NTuple{N}, b::NTuple{N}) where N =
    NTuple{N}(j - i for (i, j) in zip(a, b))

@btime g($(Ref(a))[], $(Ref(b))[])

```

Output:

```julia
  1.300 ns (0 allocations: 0 bytes)
(2.0, 3.0)

```

Using `@code_native`, I have found that the following three functions generate the same native code for `a = (1.0, 2.0)` and `b = (2.0, 5.0)`:

```julia
F(a, b) = b .- a

g(a::NTuple{N}, b::NTuple{N}) where N =
    NTuple{N}(j - i for (i, j) in zip(a, b))

h(a::NTuple{N}, b::NTuple{N}) where N =
    ntuple(i -> b[i] - a[i], N)

```

**Conclusion:** Using `g(a, b)`, we can do exactly the same as `b .- a` using `zip`.

---

<div class="post-metadata">

**Author:** ![Seif\_Shebl](https://avatars.discourse-cdn.com/v4/letter/s/eada6e/32.png) [@Seif\_Shebl](https://discourse.julialang.org/u/Seif_Shebl)\
**Post date:** [September 11, 2021, 12:18pm UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/11 "2021-09-11T12:18:28Z")

</div>

I’m not sure if I missed something but this naive thing should be really fast:

```julia
p1 = (1.0,1.0)
p2 = (1.0,1.025)
pairwise_dist(p1,p2) = ntuple(i -> p1[i]-p2[i], length(p1))

@benchmark pairwise_dist($p1,$p2)
BenchmarkTools.Trial: 10000 samples with 1000 evaluations.
 Range (min … max): 0.001 ns … 0.100 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 0.001 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 0.028 ns ± 0.044 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  █
  █▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▇ ▂
  0.001 ns Histogram: frequency by time 0.1 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

---

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [September 11, 2021, 12:57pm UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/12 "2021-09-11T12:57:21Z")

</div>

Thanks for your answer. You have to benchmark like this:

```julia
@btime pairwise_dist($Ref(p1)[],$Ref(p2)[])
  163.787 ns (5 allocations: 160 bytes)
(0.0, -0.02499999999999991)

```

Since currently your benchmark is unrealistically fast, due to the compiler having realized that you do not use the value for anything (that is what I have been told atleast)

Kind regards

---

<div class="post-metadata">

**Author:** ![Seif\_Shebl](https://avatars.discourse-cdn.com/v4/letter/s/eada6e/32.png) [@Seif\_Shebl](https://discourse.julialang.org/u/Seif_Shebl)\
**Post date:** [September 11, 2021, 4:52pm UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/13 "2021-09-11T16:52:35Z")

</div>

I’m not sure if `Ref` is very important here, but my function is as fast as the `a .- b` thing, so it doesn’t really matter.

```julia
pairwise_dist(p1,p2) = ntuple(i -> p1[i]-p2[i], length(p1))

function test_Pairs1(arr)
    s = 0.0
    for ps in arr 
        p1, p2 = ps
        s += sum(pairwise_dist(p1,p2))
    end 
    s 
end

function test_Pairs2(arr)
    s = 0.0
    for ps in arr 
        p1, p2 = ps
        s += sum(p1 .- p2)
    end 
    s 
end

arr = [( (rand(),rand()), (rand(),rand()) ) for i in 1:10^6]

@benchmark test_Pairs1($arr)
@benchmark test_Pairs2($arr)

@benchmark test_Pairs1($arr)
BenchmarkTools.Trial: 2314 samples with 1 evaluation.
 Range (min … max): 1.894 ms … 3.209 ms ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 2.113 ms ┊ GC (median): 0.00%
 Time (mean ± σ): 2.144 ms ± 114.584 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

              ▁▆██▆▅▄▃▄▁▁
  ▂▁▂▂▂▂▁▂▁▂▂▅████████████▅▄▄▄▃▃▄▃▃▃▃▃▃▃▃▃▂▂▃▂▃▂▃▂▂▂▂▂▂▂▂▂▂▂▂ ▄
  1.89 ms Histogram: frequency by time 2.61 ms <

 Memory estimate: 0 bytes, allocs estimate: 0.

@benchmark test_Pairs2($arr)
BenchmarkTools.Trial: 2318 samples with 1 evaluation.
 Range (min … max): 1.901 ms … 3.543 ms ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 2.111 ms ┊ GC (median): 0.00%
 Time (mean ± σ): 2.140 ms ± 115.493 μs ┊ GC (mean ± σ): 0.00% ± 0.00%

             ▄▆█▇██▅▅▅▂▄▁
  ▂▁▁▂▁▁▁▁▁▂▅████████████▅▅▄▃▃▃▄▃▃▃▃▃▃▂▃▃▃▃▂▃▂▃▃▂▂▃▂▂▂▂▂▂▂▂▂▂ ▄
  1.9 ms Histogram: frequency by time 2.62 ms <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [September 11, 2021, 5:10pm UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/14 "2021-09-11T17:10:56Z")

</div>

> [@genkuroki](#):
>
> ```julia
> h(a::NTuple{N}, b::NTuple{N}) where N =
> ntuple(i -> b[i] - a[i], N)
> 
> ```

@Seif_Shebl, your function looks similar to @genkuroki’s, no?

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [September 11, 2021, 5:27pm UTC](https://discourse.julialang.org/t/can-i-get-this-syntax-to-work-using-zip/68009/15 "2021-09-11T17:27:24Z")

</div>

The fast functions here should all compile down to the same thing. While nothing actually happens in `0.001 ns`, getting that does tell you that it’s reduced to something very simple.

```julia
julia> @code_typed pairwise_dist_ntuple(p1, p2)
CodeInfo(
1 ─ %1 = Base.getfield(p1, 1, true)::Float64
│ %2 = Base.getfield(p2, 1, true)::Float64
│ %3 = Base.sub_float(%1, %2)::Float64
│ %4 = Base.getfield(p1, 2, true)::Float64
│ %5 = Base.getfield(p2, 2, true)::Float64
│ %6 = Base.sub_float(%4, %5)::Float64
│ %7 = Core.tuple(%3, %6)::Tuple{Float64, Float64}
└── return %7
) => Tuple{Float64, Float64}

julia> @code_typed pairwise_dist_map(p1, p2)
CodeInfo(
1 ─ %1 = Base.getfield(p1, 1, true)::Float64
│ %2 = Base.getfield(p2, 1, true)::Float64
│ %3 = Base.sub_float(%1, %2)::Float64
│ %4 = Base.getfield(p1, 2, true)::Float64
│ %5 = Base.getfield(p2, 2, true)::Float64
│ %6 = Base.sub_float(%4, %5)::Float64
│ %7 = Core.tuple(%3, %6)::Tuple{Float64, Float64}
└── return %7
) => Tuple{Float64, Float64}

julia> @code_typed g(p1, p2) # NTuple(generator)
CodeInfo(
1 ─ %1 = Base.getfield(a, 1, true)::Float64
│ %2 = Base.getfield(b, 1, true)::Float64
│ %3 = Base.sub_float(%2, %1)::Float64
│ %4 = Base.getfield(a, 2, true)::Float64
│ %5 = Base.getfield(b, 2, true)::Float64
│ %6 = Base.sub_float(%5, %4)::Float64
│ %7 = Core.tuple(%3, %6)::Tuple{Float64, Float64}
└── return %7
) => Tuple{Float64, Float64}

```
