I'm getting a surprising result when selecting a 2D sub-slice of a slice.
Consider the following 2D int array
a := [][]int{
{0, 1, 2, 3},
{1, 2, 3, 4},
{2, 3, 4, 5},
{3, 4, 5, 6},
}
To select the top left 3x3 2D slice using ranges I would use
b := a[0:2][0:2]
I would expect the result to be
[[0 1 2] [1 2 3] [2 3 4]]
however the second index range doesn't seem to have any effect, and returns the following instead:
[[0 1 2 3] [1 2 3 4] [2 3 4 5]]
What am I missing? Can you simply not select a sub-slice like this where the dimension > 1 ?
You can't do what you want in a single step. Slices and arrays are not 2-dimensional, they are just composed to form a multi-dimensional object. See How is two dimensional array's memory representation
So with a slice expression, you just get a slice that will hold a subset of the "full" rows, and its type will be the same: [][]int. If you slice it again, you just slicing the slice of rows again.
Also note that the higher index in a slice expression is exclusive, so a[0:2] will only have 2 rows, so you should use a[0:3] or simply a[:3] instead.
To get what you want, you have to slice the rows individually like this:
b := a[0:3]
for i := range b {
b[i] = b[i][0:3]
}
fmt.Println(b)
This will output (try it on the Go Playground):
[[0 1 2] [1 2 3] [2 3 4]]
Or shorter:
b := a[:3]
for i, bi := range b {
b[i] = bi[:3]
}
Related
What is the most efficient way to create a view on array using, for example, sliding window=2
Let's say we have:
x = collect(1:1:6)
# 1 2 3 4 5 6
And I want to create a view like this:
# 1 2
# 2 3
# 3 4
# 4 5
# 5 6
So far I found only this option, but not sure if it's an optimal one:
y = Array{Float32, 2}(undef, nslides, window)
#inbounds for i in 1:window
y[:, i] = #view x[i:end-(window-i)]
end
One solution with a package (well, with my package) is this:
julia> using Tullio
julia> x = 1:6; window = 2;
julia> #tullio y[r,c] := x[r+c-1] (c in 1:window)
5×2 Matrix{Int64}:
1 2
2 3
3 4
4 5
5 6
The one liner is:
view.(Ref(x), (:).(1:length(x)-1,2:length(x)))
Testing:
julia> x=collect(1:6);
julia> view.(Ref(x), (:).(1:length(x)-1,2:length(x)))
5-element Array{SubArray{Int64,1,Array{Int64,1},Tuple{UnitRange{Int64}},true},1}:
[1, 2]
[2, 3]
[3, 4]
[4, 5]
[5, 6]
Explanation:
creation of views is vectorized by the dot operator .
we do not want to vectorize on elements of x so use Ref(x) instead
(:) is just a shorter form for UnitRange and again we use the dot operator . to vectorize
I used 2 as the Window size but of course you can write view.(Ref(x), (:).(1:length(x)-(window-1),window:length(x)))
EDIT:
If you want rather a library function this would work for you:
julia> using ImageFiltering
julia> mapwindow(collect, x, 0:1,border=Inner())
5-element OffsetArray(::Array{Array{Int64,1},1}, 1:5) with eltype Array{Int64,1} with indices 1:5:
[1, 2]
[2, 3]
[3, 4]
[4, 5]
[5, 6]
Of course you could put them the function that you want to run on the sliding window rather than just collect.
In Julia vec reshapes multidimensional arrays into one-dimension arrays.
However it doesn't work for arrays of arrays or arrays of tuples.
A part from using array comprehension, is there another way to flatten arrays of arrays/tuples? Or arrays of arrays/tuples of arrays/tuples? Or ...
Iterators.flatten(x) creates a generator that iterates over each element of x. It can handle some of the cases you describe, eg
julia> collect(Iterators.flatten([(1,2,3),[4,5],6]))
6-element Array{Any,1}:
1
2
3
4
5
6
If you have arrays of arrays of arrays and tuples, you should probably reconsider your data structure because it doesn't sound type stable. However, you can use multiple calls to flatten, eg
julia> collect(Iterators.flatten([(1,2,[3,3,3,3]),[4,5],6]))
6-element Array{Any,1}:
1
2
[3, 3, 3, 3]
4
5
6
julia> collect(Iterators.flatten(Iterators.flatten([(1,2,[3,3,3,3]),[4,5],6])))
9-element Array{Any,1}:
1
2
3
3
3
3
4
5
6
Note how all of my example return an Array{Any,1}. That is a bad sign for performance, because it means the compiler could not determine a single concrete type for the elements of the output array. I chose these example because the way I read your question it sounded like you may have type unstable containers already.
In order to flatten an array of arrays, you can simply use vcat() like this:
julia> A = [[1,2,3],[4,5], [6,7]]
Vector{Int64}[3]
Int64[3]
Int64[2]
Int64[2]
julia> flat = vcat(A...)
Int64[7]
1
2
3
4
5
6
7
The simplest way is to apply the ellipsis ... twice.
A = [[1,2,3],[4,5], [6,7]]
flat = [(A...)...]
println(flat)
The output would be
[1, 2, 3, 4, 5, 6, 7].
If you use VectorOfArray from RecursiveArrayTools.jl, it uses the indexing fallback to provide convert(Array,A) for a VectorOfArray A.
julia> using RecursiveArrayTools
julia> A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3-element Array{Array{Int64,1},1}:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
julia> VA = VectorOfArray(A)
3-element Array{Array{Int64,1},1}:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
First of it acts as a lazy wrapper for doing the indexing without conversion:
julia> VA[1,3]
7
Note that columns are the separate arrays so that way it's still "column-major" (i.e. efficient to index down columns). But then it has a straight conversion:
julia> convert(Array,VA)
3×3 Array{Int64,2}:
1 4 7
2 5 8
3 6 9
The other way to handle this conversion is to do something like hcat(A...), but that's slow if you have a lot of arrays you're splatting!
Now, you may think: what about writing a function that pre-allocates the matrix, then loops through and fills it? That's almost what convert on the VectorOfArray works, except the fallback that convert uses here utilizes Tim Holy's Cartesian machinery. At one point, I wrote that function:
function vecvec_to_mat(vecvec)
mat = Matrix{eltype(eltype(vecvec))}(length(vecvec),length(vecvec[1]))
for i in 1:length(vecvec)
mat[i,:] .= vecvec[i]
end
mat
end
but I have since gotten rid of it because the fallback was much faster. So, YMMV but that's a few ways to solve your problem.
for Julia 0.7x:
for Arrays:
flat(arr::Array) = mapreduce(x -> isa(x, Array) ? flat(x) : x,
append!, arr,init=[])
for Tuples:
flat(arr::Tuple) = mapreduce(x -> isa(x, Tuple) ? flat(x) : x,
append!, arr,init=[])
Works for arbitrary depth.
see: https://rosettacode.org/wiki/Flatten_a_list#Julia
Code for Array/Tuple:
function flatten(arr)
rst = Any[]
grep(v) = for x in v
if isa(x, Tuple) || isa(x, Array)
grep(x)
else push!(rst, x) end
end
grep(arr)
rst
end
I need to copy a part of a 3D array.
I have the indexes of start and end of the copy.
For example 2D array:
[[2 2 3 4 5]
[2 3 3 4 5]
[2 3 4 4 5]
[2 3 4 5 5]
[2 3 4 5 6]]
starting index, end index are:
mini = [2, 1]
maxi = [4, 3]
So the result should be:
[[3 4 4]
[3 4 5]]
I can write:
result = matrix[mini[0]:maxi[0], mini[1]:maxi[1]]
Is there a way to do it generally ? for 3Dim or NDim arrays ?
The trick here is realizing what the indexing syntax is under the hood. This:
result = matrix[mini[0]:maxi[0], mini[1]:maxi[1]]
Is shorthand in python (not just numpy) for:
indices = slice(mini[0], maxi[0]), slice(mini[1], maxi[1])
result = matrix[indices]
So we just need to generate indices dynamically:
lower = [2, 1, ...]
upper = [4, 3, ...]
indices = tuple(np.s_[l:u] for l, u in zip(lower, upper))
result = matrix_nd[indices]
np.s_[a:b] is a shorthand for slice(a, b). Here we build a tuple containing as many slices as you have values in lower and upper
What you are looking for is the slice object, see that example:
matrix = np.random.rand(4,5)
mini = [2, 1]
maxi = [4, 3]
slices=[slice(b,e) for b, e in zip(mini,maxi)]
print(slices)
print(matrix[slices])
print(matrix[mini[0]:maxi[0], mini[1]:maxi[1]])
I've recently been messing around with Go and I wanted to see how it would be to delete an element from a two-dimensional slice.
For deleting an element from a one-dimensional slice, I can successfully use:
data = append(data[:i], data[i+1:]...)
However, with a two-dimensional slice, using:
data = append(data[i][:j], data[i][j+1:]...)
throws the error:
cannot use append(data[i][:j], data[i][j+1:]...) (type []string) as type [][]string in assignment
Would tackling this require a different approach?
A 2D slice in Go is nothing more than a slice of slices. So if you want to remove an element from this 2D slice, effectively you still only have to remove an element from a slice (which is an element of another slice).
There is nothing more involved. Only thing you have to look out is that when you remove an element from the row-slice, the result will only be the "new" value of the row (an element) of the "outer" slice, and not the 2D slice itself. So you have to assign the result to an element of the outer slice, to the row whose element you just removed:
// Remove element at the ith row and jth column:
s[i] = append(s[i][:j], s[i][j+1:]...)
Note that this is identical to the simple "removal from slice" if we substitute s[i] with a (not surprisingly, because s[i] denotes the "row-slice" whose jth element we're removing):
a = append(a[:j], a[j+1:]...)
See this complete example:
s := [][]int{
{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 10, 11},
}
fmt.Println(s)
// Delete element s[1][2] (which is 6)
i, j := 1, 2
s[i] = append(s[i][:j], s[i][j+1:]...)
fmt.Println(s)
Output (try it on the Go Playground):
[[0 1 2 3] [4 5 6 7] [8 9 10 11]]
[[0 1 2 3] [4 5 7] [8 9 10 11]]
Here is one of the possible approaches Go Playground.
b := [][]int{
[]int{1, 2, 3, 4},
[]int{5, 6, 7, 8},
[]int{9, 0, -1, -2},
[]int{-3, -4, -5, -6},
}
print2D(b)
i, j := 2, 2
tmp := append(b[i][:j], b[i][j+1:]...)
c := append(b[:i], tmp)
c = append(c, b[i+1:]...)
print2D(c)
Basically I am extracting the i-th row, remove the element from it append(b[i][:j], b[i][j+1:]...) and then put this row between the rows.
If someone would tell how to append many elements, it would look even nicer.
I have a cell array containing 5 1x2 arrays. Is there any way to find the most repeated element? I think I cannot use the "mode" function. I looked it up on the internet and could not find a solution about the problem. Everybody keeps talking about cells array with strings.
The cell array I'm using is like this:
{[1 2], [2 5], [3 4], [1 2], [0 4]}
I would like MATLAB to find [1 2] as the most repeated element.
Thank you in advance.
For uniformly structured cell array (2 elements per cell) case
%// Convert the uniformly structured data to a 2D numeric array
Anum = vertcat(A{:})
%// ID unique rows and ID all rows based on those
[~,unqID,ID ] = unique(Anum,'rows')
%// Use 'mode' on ID and then index into unqID to get the index of
%// the most frequently occurring cell and finally index into the
%// input cell array with that index to get the desired output
out = A{unqID(mode(ID))}
Thus, for the given input data -
A = {[1 2], [2 5], [3 4], [1 2], [0 4]}
You would have -
out =
1 2
More generic case with cells of row vectors
If you are dealing with a cell array that has arbitrary sized row vectors in each cell, you can use this technique -
%// Get all elements of A
A_ele = [A{:}]
%// Get lengths of each cell
lens = cellfun('length',A)
%// Setup a 2D numeric array corresponding to the input cell array
A_num = zeros(max(lens),numel(lens))+max(A_ele)+1
A_num(bsxfun(#ge,lens,[1:max(lens)]')) = A_ele %//'
%// ID each row, find the mode with those & finally have the desired output
[unqrows,unqID,ID ] = unique(A_num.','rows') %//'
out = A{unqID(mode(ID))}
Thus, if you have input as -
A = {[1 2], [2 5], [3 4], [1 2], [0 4], [1 2 1],[9],[7 2 6 3]}
The output would still be -
out =
1 2
This works for a general cell array A:
A = {[4 2] [2 5] [4 2] [1 2 1] [9] [7 2 6 3] [1 2 1] [1 2 1] [7 9]}; %// example data
[ii, jj] = ndgrid(1:numel(A)); %// ii, jj describe all pairs of elements from A
comp = cellfun(#isequal, A(ii), A(jj)); %// test each pair for equality
[~, ind] = max(sum(comp,1)); %// get index of (first) most repeated element
result = A{ii(ind)}; %// index into A to get result