# Generic function for pairwise operations

**URL:** https://discourse.julialang.org/t/generic-function-for-pairwise-operations/1041
**Category:** General Usage
**Created:** [December 19, 2016, 3:00pm UTC](https://discourse.julialang.org/t/generic-function-for-pairwise-operations/1041 "2016-12-19T15:00:05Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)
#### Post date: [December 19, 2016, 3:00pm UTC](https://discourse.julialang.org/t/generic-function-for-pairwise-operations/1041/1 "2016-12-19T15:00:05Z")

</div>

A very commonly used design pattern is to apply a function to all unique pairs of elements in a container, e.g.

```julia
f(x,y) = x*y
a = randn(5)
ret = eltype(a)[] #the example returns a vector, but in this case an UpperTriangular Matrix might be better.
for i in 1:(length(a-1))
   for j in (i+1):length(a)
      push!(ret, f(a[i], a[j]))
   end
end

```

(see e.g. [Fast Numeric Computation in Julia](http://julialang.org/blog/2013/09/fast-numeric) for a use of pairwise), but it could also apply to all pairwise combination of columns or rows in a Matrix or higher-dimensional arrays.  
Julia provides `map` for elementwise operations. Is there such a function for pairwise operations? Alternatively, if someone were to implement such a function, where would it be put? It should be so relatively general that it should be close to Base, I think to be really interesting, or perhaps somewhere like Iterators.jl?  
Distances.jl has a `pairwise` function that implements some of this functionality efficiently, but AFAICS not all of it.  
Thanks!

---

<div class="post-metadata">

### Author: ![johnmyleswhite](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johnmyleswhite/32/31_2.png) [@johnmyleswhite](https://discourse.julialang.org/u/johnmyleswhite)
#### Post date: [December 19, 2016, 3:31pm UTC](https://discourse.julialang.org/t/generic-function-for-pairwise-operations/1041/2 "2016-12-19T15:31:53Z")

</div>

I’m not aware of such functionality. My sense is that there’s a lot of useful abstractions that aren’t quite useful enough for someone to have built them, made them robust and decided to maintain them in the future.

In general, I very strongly encourage building all new functionality in a package that you both control and maintain. Base might be a good place for this, but it’s much better for everyone to start with functionality outside of Base.

On a sidenote, I’d want to know whether you want `pairwise_map(f, M)`, which applies `f` to all pairs of entries in `M`, or whether you want `map(f, pairs(x, y))`, which takes two iterators and combines them into a single iterator that is mapped into a vector or other flat iterable.

---

<div class="post-metadata">

### Author: ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)
#### Post date: [December 19, 2016, 6:18pm UTC](https://discourse.julialang.org/t/generic-function-for-pairwise-operations/1041/3 "2016-12-19T18:18:00Z")

</div>

Ah, yes, I had a feeling the answer might be something like that. Well I definitely would find something like this useful so I might give it a stab sometime (or @ChrisRackauckas would it belong in [GitHub - ChrisRackauckas/VectorizedRoutines.jl: Familiar vectorized routines from R/Python/MATLAB, plus some more.](https://github.com/ChrisRackauckas/VectorizedRoutines.jl) ?)

I think I’d want `pairwise_map(f, M)`, perhaps with `pairwise_mapslices(f, M)` for multidimensional arrays. The return type is also tricky - maybe it should be an UpperTriangular (for linear containers)?

---

<div class="post-metadata">

### Author: ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)
#### Post date: [December 19, 2016, 6:34pm UTC](https://discourse.julialang.org/t/generic-function-for-pairwise-operations/1041/4 "2016-12-19T18:34:59Z")

</div>

> [@mkborregaard](#):
>
> (or @ChrisRackauckas would it belong in [GitHub - ChrisRackauckas/VectorizedRoutines.jl: Familiar vectorized routines from R/Python/MATLAB, plus some more.](https://github.com/ChrisRackauckas/VectorizedRoutines.jl) ?)

Yes, this is exactly the kind of stuff I’m gathering there if it has no other home!

---

<div class="post-metadata">

### Author: ![johnmyleswhite](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johnmyleswhite/32/31_2.png) [@johnmyleswhite](https://discourse.julialang.org/u/johnmyleswhite)
#### Post date: [December 19, 2016, 7:03pm UTC](https://discourse.julialang.org/t/generic-function-for-pairwise-operations/1041/5 "2016-12-19T19:03:58Z")

</div>

> [@mkborregaard](#):
>
> The return type is also tricky - maybe it should be an UpperTriangular (for linear containers)

This sounds like you’re assuming that the function being applied pairwise is symmetric, no?

---

<div class="post-metadata">

### Author: ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)
#### Post date: [December 19, 2016, 7:40pm UTC](https://discourse.julialang.org/t/generic-function-for-pairwise-operations/1041/6 "2016-12-19T19:40:10Z")

</div>

argh, yes I was. Good point!

---

<div class="post-metadata">

### Author: ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)
#### Post date: [January 23, 2017, 11:28pm UTC](https://discourse.julialang.org/t/generic-function-for-pairwise-operations/1041/7 "2017-01-23T23:28:07Z")

</div>

For cross-reference, the discussion continued here [https://github.com/ChrisRackauckas/VectorizedRoutines.jl/issues/8](https://github.com/ChrisRackauckas/VectorizedRoutines.jl/issues/8) and there is now a PR here: [https://github.com/ChrisRackauckas/VectorizedRoutines.jl/pull/9](https://github.com/ChrisRackauckas/VectorizedRoutines.jl/pull/9)

---

<div class="post-metadata">

### Author: ![sergevic](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sergevic/32/9958_2.png) [@sergevic](https://discourse.julialang.org/u/sergevic)
#### Post date: [March 18, 2020, 6:50pm UTC](https://discourse.julialang.org/t/generic-function-for-pairwise-operations/1041/8 "2020-03-18T18:50:58Z")

</div>

@mkborregaard, your code doesn’t work… I get the following error with Julia 1.1.1:

`MethodError: no method matching -(::Array{Float64,1}, ::Int64) Closest candidates are: -(!Matched::Complex{Bool}, ::Real) at complex.jl:298 -(!Matched::Missing, ::Number) at missing.jl:97 -(!Matched::Base.CoreLogging.LogLevel, ::Integer) at logging.jl:107 ... top-level scope at none:0`

What is wrong?

---

<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: [March 18, 2020, 7:23pm UTC](https://discourse.julialang.org/t/generic-function-for-pairwise-operations/1041/9 "2020-03-18T19:23:59Z")

</div>

I presume it was meant to be `for i in 1:(length(a)-1)`. Since we’re here, note that this is the same as

```julia
[f(x,y) for (i,x) in enumerate(a), (j,y) in enumerate(a) if i>j]

```

---

<div class="post-metadata">

### Author: ![sergevic](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sergevic/32/9958_2.png) [@sergevic](https://discourse.julialang.org/u/sergevic)
#### Post date: [March 18, 2020, 7:37pm UTC](https://discourse.julialang.org/t/generic-function-for-pairwise-operations/1041/10 "2020-03-18T19:37:51Z")

</div>

Ah! Didn’t think about the array comprehesion! Good!
