# `hcat` with generator

I find myself wanting to write code of the kind

``````hcat(f(i) for i = 1:n)
``````

where `f(i)` would be a function computing the `i`th column - or possibly multiple columns - of a matrix.
but I end up getting something weird, `1×1 Array{Base.Generator{UnitRange{Int64},##3#4},2}: Base.Generator{UnitRange{Int64},##3#4}(#3,1:3)`

Is such construction feasible? wanted? Is there an alternative simple one-liner that one could use?

1 Like

Maybe you could use `collect`?

``````A = reshape(1:12, 3, 4)
f(A,i) = A[:,i]
hcat(collect(f(A,i) for i = 1:4)...)
``````

clunky, but works. Thank you. (My question is still valid though I believe?)

Or just use an array comprehension instead of a generator:

``````hcat([f(A,i) for i = 1:4]...)
``````
1 Like

That’s in fact how I ended up doing it. Still feels like one step too many.

On 0.6 you could take advantage of dot fusion and do something along the following lines

``````f(r) = (1:3) .+ 3 .* (r' .- 1)
f(1:4)
``````

On 0.5 you can do the same but won’t be as efficient (you would have to write another function so it doesn’t create unnecessary temporaries, except for the transposition)

``````g(i, j) =  i + 3 * (j - 1)
f(r) = g.(1:3, r')
f(1:4)
``````
1 Like

By defining the following function:

``````function genmat(g)
itr = start(g)
done(g,itr) && error("generator must provide at least one column block")
(v,itr) = next(g,itr)
l = size(v,1)
vlist = [vec(v)]
while !done(g,itr)
(v,itr) = next(g,itr)
size(v,1) == l || error("all columns must be of same length")
push!(vlist,vec(v))
end
m = vcat(vlist...)
return reshape(m,l,length(m)÷l)
end
``````

We can simply do:
`genmat((f(A,i) for i=1:4))`
but also:
`genmat((f(A,i:i+1) for i=1:3))`
and get an error whith an empty generator, etc. Might be worth the trouble.
Regarding efficiency, it is hard to avoid some allocations without knowing in advance how many and in what shape the column blocks the generator will produce.

I like this, but could one not just rename your `genmat` to `vcat` ?`(CORR.: I meant`hcat`)

`vcat` is already taken and has a semantic meaning of vertical concatenation. IMHO function names in Julia are very central, and should be very carefully constructed and shared between methods to enable maximum utility when reused. But a name other than `genmat` is certainly welcome.

``````hcat((f(A,i) for i = 1:4)...)
``````

works and doesn’t generate an intermediate array.

2 Likes

`hcat` and `genmat` both do some allocations. Benchmarking shows `genmat` does less, and `genmat` is also 8x faster (on my machine).
typo - I meant `hcat`. I am asking why not just change the meaning of `hcat(::Generator)`
That would be incompatible with what `hcat` does; it does not concatenate all members of its argument, but rather all its arugments.