Build array iterating over multiple indices in Julia - arrays

I want to obtain the following result with a more elegant syntax
julia> collect(Iterators.flatten([[(x,y) for y in 1:x] for x in 1:3]))
6-element Array{Tuple{Int64,Int64},1}:
(1, 1)
(2, 1)
(2, 2)
(3, 1)
(3, 2)
(3, 3)
I tried something like [(x,y) for y in 1:x, x in 1:3] but I get ERROR: UndefVarError: x not defined.

Just reverse the order of variables like this:
julia> [(x,y) for x in 1:3 for y in 1:x]
6-element Array{Tuple{Int64,Int64},1}:
(1, 1)
(2, 1)
(2, 2)
(3, 1)
(3, 2)
(3, 3)

I used to have also been struggled to remember the variable order. Until one day someone told me a secret: just treat the order of for loop in the list comprehension as usual except that the body is moved to the front.
For example, in normal order we write:
for x in 1:3
for y in 1:x
# do sth
end
end
Now we move the body part to the front and we have [ #= do sth =# for x in 1:3 for y in 1:x]

Related

Can I get a single answer in pydatalog ask?

I'm using pydatalog to solve a path-planning problem (just an example). I want one path from the begin state to the end state, i.e. one answer. As far as I can tell, ask() yields a list of all answers and I would like to generate the answers lazily.
A second question: notice I had to define member/2 where I thought I could say
(Z in Freesquares) and
~(Z in P1)
But I get the error
TypeError: argument of type 'bool' is not iterable
Any cleaner way to write that code?
Thanks!
# Defn of adjacent is missing. For example (r,c) is adjacent to (r+1,c), (r,c+1), (r-1,c), (r,c-1)
create_terms('path', 'Begin', 'Current', 'End', 'FreeSquares', 'Path', 'P1')
path(Begin, Current, End, FreeSquares, Path) <= adjacent(Current, End) & (Path==[])
path(Begin, Current, End, FreeSquares, Path) <= \
adjacent(Current, Z) & ~(Z == Begin) & ~(Z == End) & member(Z, FreeSquares) & \
path(Begin, Z, End, FreeSquares, P1) & ~member(Z, P1) & (Path == [Z] + P1)
ask('path((3,3), (3,3), (1,1), [(1,1), (1,2), (2,1), (2,2), (2,3), (3,1), (3,3)], X)').answers
[(((2, 3), (2, 2), (1, 2)),), (((2, 3), (2, 2), (2, 1)),)]

How to do a cartesian product of a variable number of lists in Julia?

For each value j in the set {1, 2, ..., n} where the value of n can vary (it is some variable in my program that can be different depending on the inputs from the user), I have an array A_j. I would like to obtain the cartesian product of all the arrays A_j, so that I can then iterate through that cartesian product (taking one element from each A_1, A_2, ... A_n to get a tuple (a_1, a_2, ..., a_n) in A_1 x A_2 x ... x A_n). How would I accomplish this in Julia?
Use Iterators.product:
help?> Iterators.product
product(iters...)
Return an iterator over the product of several iterators. Each generated
element is a tuple whose ith element comes from the ith argument iterator.
The first iterator changes the fastest.
Examples
≡≡≡≡≡≡≡≡≡≡
julia> collect(Iterators.product(1:2, 3:5))
2×3 Matrix{Tuple{Int64, Int64}}:
(1, 3) (1, 4) (1, 5)
(2, 3) (2, 4) (2, 5)

Find total number of ways possible to create an array of size M

Suppose I have M = 2 and N = 5 and K = 2 where
M = size of array
N = Maximum number that can be present as an array element
K = Minimum number that can be present as an array element.
So how do I find the number of possible ways to create an array using the above conditions. Also the current number should be not be greater than the previous element.
The arrays created using the above conditions are
[5,5],[5,4],[5,3],[5,2],[4,4],[4,3],[4,2],[3,3],[3,2],[2,2]
i.e 10 array can be created from the above conditions.
I tried doing it by using combinations and factorials, but not getting the desired output. Any help would be appreciated.
Assuming you are just interested in the number of combinations the formula is -
(N-K+M)!/(M!(N-K+1)!)
See more here
This is known as a combinations_with_replacement: combination because the order doesn't matter (or it would be a permutation), and with replacement because elements can be repeated, like [5, 5].
list(itertools.combinations_with_replacement(range(2, 6), 2))
# [(2, 2), (2, 3), (2, 4), (2, 5), (3, 3), (3, 4), (3, 5), (4, 4), (4, 5), (5, 5)]
If you want the exact ones you listed, you will have to reverse each element, and the list itself.
list(reversed([tuple(reversed(element)) for element in itertools.combinations_with_replacement(range(2,6), 2)]))

Julia: Cannot append tuple to array

I would like to have an array of tuples. However it seems I cannot append a tuple to it. Here is a minimal code example that raises the error.
julia> a = [(1,1),(2,2)]
2-element Array{Tuple{Int64,Int64},1}:
(1, 1)
(2, 2)
julia> append!(a, (3,3) )
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type Tuple{Int64,Int64}
This may have arisen from a call to the constructor Tuple{Int64,Int64}(...),
since type constructors fall back to convert methods.
Stacktrace:
[1] _append!(::Array{Tuple{Int64,Int64},1}, ::Base.HasLength, ::Tuple{Int64,Int64}) at ./array.jl:644
[2] append!(::Array{Tuple{Int64,Int64},1}, ::Tuple{Int64,Int64}) at ./array.jl:637
Is something wrong with my syntax? I don't get why it complains that it has to convert a number to a tuple. What gives?
append! adds all of the individual elements of another collection to the existing object. Julia raises the error here because (3, 3) is a collection of two integers and it cannot reconcile an individual integer of type Int64 with the array's Tuple{Int64,Int64} type.
The method you need is push!, which will add one or more individual items to an existing collection:
julia> push!(a, (3, 3))
3-element Array{Tuple{Int64,Int64},1}:
(1, 1)
(2, 2)
(3, 3)
The individual item, the tuple (3, 3), was successfully pushed onto the array a.
To accomplish the same task with append!, the tuple needs to be contained in a collection of some sort itself, such as an array:
julia> append!(a, [(4, 4)])
4-element Array{Tuple{Int64,Int64},1}:
(1, 1)
(2, 2)
(3, 3)
(4, 4)
This is documented on the collections page here.

How to use Data.List.iterate on tuple

The expression iterate (1+) 1 evaluates to [1, 2, 3, ...]
Can I do something like iterate ((1+) (1+)) (1, 1) so I can get [(1, 1), (2, 2), ... ] ? If yes, what is the syntax ?
This syntax should work fine:
iterate (\(x,y) -> (x+1, y+1)) (1, 1)
There are also many other ways to skin this cat:
iterate (bimap (1+) (1+)) (1, 1)
iterate ((1+) *** (1+)) (1, 1)
map (\x -> (x,x)) $ iterate (1+) 1
join (,) <$> iterate (1+) 1
[(x, x) | x <- [1..]]
...and many more.
Expanding on Daniel Wagner's answer -- Data.List's iterate takes a function as a first argument. The type signature of iterate is
(a -> a) -> a -> [a]
Meaning that the function in the first argument simply has to return the same type as it ingests. This can be an anonymous function, as show in Daniel's answer, or a function name. For example; his example could be rewritten using a named function like so:
import Data.List (iterate)
addOne (x, y) = (x + 1, y + 1)
iterate addOne (1, 1)

Resources