How to sum tuple elements

x is a matrix 5x5 of tuples. How can I filter the tuples where the sum of their elements is 6?

numbers = [1,2,3,4,5]
x = collect(Iterators.product(numbers, numbers))

Maybe

julia> x = collect(Iterators.product(numbers, numbers))
5Ă—5 Matrix{Tuple{Int64, Int64}}:
 (1, 1)  (1, 2)  (1, 3)  (1, 4)  (1, 5)
 (2, 1)  (2, 2)  (2, 3)  (2, 4)  (2, 5)
 (3, 1)  (3, 2)  (3, 3)  (3, 4)  (3, 5)
 (4, 1)  (4, 2)  (4, 3)  (4, 4)  (4, 5)
 (5, 1)  (5, 2)  (5, 3)  (5, 4)  (5, 5)

julia> (x -> sum(x) .== 6).(x)
5Ă—5 BitMatrix:
 0  0  0  0  1
 0  0  0  1  0
 0  0  1  0  0
 0  1  0  0  0
 1  0  0  0  0

?

1 Like

OK. But how can filter the tuples that have value 1? Like (1, 5), (2, 4), …
I tried to use:
y = filter((x -> sum(x) .== 6 .x), x)
but I got an error.

julia> x = [ (1,2) (2,4)
             (1,1) (1,5) ]
2Ă—2 Matrix{Tuple{Int64, Int64}}:
 (1, 2)  (2, 4)
 (1, 1)  (1, 5)

julia> filter(t -> sum(t) == 6, x)
2-element Vector{Tuple{Int64, Int64}}:
 (2, 4)
 (1, 5)


1 Like

@leandromartinez98 Sorry, your solution gives an error.
I don’t understand why the complete solution gives an error:

numbers = [1,2,3,4,5]
x = collect(Iterators.product(numbers, numbers))
y = filter(t -> sum(t) == 6, x)

It doesn’t here, just copying and pasting your code:

julia
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.6.2 (2021-07-14)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> numbers = [1,2,3,4,5]
5-element Vector{Int64}:
 1
 2
 3
 4
 5

julia> x = collect(Iterators.product(numbers, numbers))
5Ă—5 Matrix{Tuple{Int64, Int64}}:
 (1, 1)  (1, 2)  (1, 3)  (1, 4)  (1, 5)
 (2, 1)  (2, 2)  (2, 3)  (2, 4)  (2, 5)
 (3, 1)  (3, 2)  (3, 3)  (3, 4)  (3, 5)
 (4, 1)  (4, 2)  (4, 3)  (4, 4)  (4, 5)
 (5, 1)  (5, 2)  (5, 3)  (5, 4)  (5, 5)

julia> y = filter(t -> sum(t) == 6, x)
5-element Vector{Tuple{Int64, Int64}}:
 (5, 1)
 (4, 2)
 (3, 3)
 (2, 4)
 (1, 5)

julia> 

3 Likes

If you filter, what kind of shape do you expect the object to have? It’s a matrix, what does it mean to just get rid of elements in the matrix?

Sorry, you’re right. I must have done something wrong.
It is OK in the REPL but in Vscode gives the error MethodError: objects of type Int64 are not callable.

You’re right. But I am only interested in some elements of the matrix and I want to list them.

FWIW, if you don’t care of a matrix shape and only want the tuples which give the sum 6, then you may rewrite your code without collecting the product:

julia> numbers = 1:5;

julia> x = Iterators.product(numbers, numbers); # or x = ((k, l) for k in numbers for l in numbers)

julia> ts = [tup for tup in x if sum(tup) == 6]
5-element Vector{Tuple{Int64, Int64}}:
 (5, 1)
 (4, 2)
 (3, 3)
 (2, 4)
 (1, 5)

The same can be written as ts = collect(Iterators.filter(tup -> sum(tup) == 6, x)) but doesn’t work for eager filter (looks like filter isn’t defined for lazy iterables).

3 Likes

Here is what I learnt, where an error said some type “are not callable”, there is somewhere in your code you used a function name as variable.

For example:

               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.4.2 (2020-05-23)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> sum  = 6
6

julia> sum([1,2])
ERROR: MethodError: objects of type Int64 are not callable
Stacktrace:
 [1] top-level scope at REPL[2]:1

1 Like

Thank you. I had a variable called sum in Vscode but not in REPL.

What do you mean for eager filter?

Base.filter is eager, i.e. it produces all the values once called.
Iterators.filter is lazy, i.e. it produces the values one by one on demand.

Because of that, Base.filter is not defined for an arbitrary iterable, only for certain types which are guaranteed to have a finite length. And, as it turns out, it doesn’t work with generators. Iterators.filter works with any iterable because of laziness.

So, this works:

nums = (n for n in 1:10)
evens = [n for n in nums if iseven(n)]

This stops with an error because Base.filter doesn’t work with generators (because they potentially may produce an infinite sequence):

filter(iseven, nums)
3 Likes

FWIW, some benchmarks with the classical Matlab-like alternative:

using BenchmarkTools
f(x,n) = x[sum.(x) .== n]
g(x,n) = filter(t -> sum(t) == n, x)

numbers = 1:100
x = collect(Iterators.product(numbers, numbers))
n = 100
f(x,n) == g(x,n)  # true

@btime f($x,$n)   # 4.4 ÎĽs (4 allocations: 7.3 KiB)
@btime g($x,$n)   # 8.7 ÎĽs (3 allocations: 156.3 KiB)