Gustorn
Gustorn

Reputation: 455

Vectors of length N with elements from another vector (with repetition)

Is there any easy way to generate an array of permutations of length N, drawn from k values? Example:

N = 2
k = [[0 0], [0 1], [1 0], [1 1]]
Permutations = [
    [[0 0], [0 0]],
    [[0 0], [0 1]],
    [[0 0], [1 0]],
    [[0 0], [1 1]],
    [[0 1], [0 0]],
    [[0 1], [0 1]],
    [[0 1], [1 0]],
    [[0 1], [1 1]],
    ...
]

An important note here: If possible, I'd like the result to be arrays all the way down (the product function in the Iterators package generates tuples)

If it helps, the Haskell equivalent would be: replicateM 2 [[0, 0], [0, 1], [1, 0], [1, 1]]

Just in case there's a more idiomatic way to achieve what I'm trying to do, here's the function I'm writing:

function generate_states(length)
    # "tuples" contains what I want, but it needs a lot of transformation to 
    # be usable later
    tuples = [collect(t) for t in
              product([product(0:1, 0:1) for _ in 1:length]...)]
    states = collect(distinct(imap(x -> kron([[i...] for i in x]...), tuples)))
    return states
end

Which works, and does what I want, but ideally I'd like it to look something like this:

function generate_states(length)
    arrays = replicateM(3, Array[[0 0], [0 1], [1 0], [1 1]])
    states = collect(distinct(imap(x -> kron(x...), arrays)))
    return states
end

Upvotes: 3

Views: 287

Answers (2)

David P. Sanders
David P. Sanders

Reputation: 5325

There's a simple solution with tuples as follows:

K = [(0,0), (0,1), (1,0), (1,1)]

vec( [(i,j) for i in K, j in K] )

If you really need arrays (why do you need this?) you can do

K2 = [ [a...] for a in K ]

[ a for a in vec( [(i,j) for i in K2, j in K2] ) ]

If you need arrays of arrays then that is also possible, but even more messy. So the question is, can you really not get use tuples of tuples?

Upvotes: 3

Dan Getz
Dan Getz

Reputation: 18217

UPDATE / FIX

The question actually wants to generate all the sequences of length N of elements from k.

This could be achieved using:

using Iterators   # install package with `Pkg.add("Iterators")`

N = 2
k = Array[[0 0], [0 1], [1 0], [1 1]]
res = [Array[e...] for e in product(fill(k,N)...)]

OLDER INTERPRETATION - permutations of objects

collect(combinations(['a','b','c','d'],2)) generates the right collection disregarding the elements being permuted.

The specific elements in your code [0 0] are row vectors (i.e. 1x2 matrices). This is more awkward than column vectors in Julia. The example with column vectors is:

julia> combinations(Array[[0,0],[0,1],[1,0],[1,1]],2) |> collect
6-element Array{Array{Array{Int64,1},1},1}:
 [[0,0],[0,1]]
 [[0,0],[1,0]]
 [[0,0],[1,1]]
 [[0,1],[1,0]]
 [[0,1],[1,1]]
 [[1,0],[1,1]]

Note the explicit typing of [] to prevent flattening of internal elements by vcat. With row vectors, as in the OP:

combinations(Array[[0 0],[0 1],[1 0],[1 1]],2) |> collect

(standard output is messy)

Upvotes: 4

Related Questions