I'm trying to access a part of a multidimensional array in Matlab - it could be done like this: X(2:3, 1:20, 5, 4:7)
However, neither the number of elements, nor the ranges are fixed, so I want to provide the indices from arrays - for the above example they'd be
ind1 = [2 1 5 4];
ind2 = [3 20 5 7];
For a fixed number of dimensions this is not a problem (X(ind1(1):ind2(1),...), but since they are not I'm not sure how to implement this in Matlab. Is there a way? Or should I approach this differently?
Using comma separated lists you can make it a more quick and friendly:
% some test data
ind1 = [2 1 5 4];
ind2 = [3 20 5 7];
X = randi(99,20,20,20,20);
% get all subscripts in column format
vecs = arrayfun(#colon,ind1,ind2,'un',0);
% extract the values
result = X(vecs{:});
There probably is a more elegant way, but this is a difficult problem so here is one solution:
% some test data
ind1 = [2 1 5 4];
ind2 = [3 20 5 7];
X = randi(99,20,20,20,20);
% get all subscripts in column format
vecs = arrayfun(#colon,ind1,ind2,'Uniformoutput',false);
subs = combvec(vecs{:}).';
% manual sub2ind for a matrix where each row contains one subscript
sizeX = size(X);
idx = cumprod([1 sizeX(1:end-1)])*(subs - [zeros(size(subs,1),1) ones(size(subs,1),size(subs,2)-1)]).';
% reshape
result = reshape(X(idx),ind2-ind1+1);
Subscripts to indices conversion based on Gnovices answer in Indexing of unknown dimensional matrix
Related
Lets say I have the following array:
board = np.random.randint(1, 9, size=(2, 5))
How do I remove duplicates from each element in the array
e.g.
[[6 1 2 8 4]
[8 3 2 3 6]]
So here there are two 3s, and I want one of those to be deleted, how can I perform such an action?
Given your example, it seems that you don't want repetition relatively to rows. You may be interested in numpy.random.choice and try something like this:
import numpy as np
nb_lines = 2
nb_columns = 5
min_value = 1
max_value = 9
range_value = max_value-min_value
# The number of columns should be <= than the integer range to have a solution
assert(range_value+1 >= nb_columns)
board = min_value + np.array([
np.random.choice(np.arange(range_value+1), nb_columns, replace=False)
for l in range(nb_lines)
])
print(board)
Output:
% python3 script.py
[[7 4 6 3 1]
[2 8 6 4 3]]
I have a cell array as shown below:
a = {[1 2 3] [5 3 6] [9 1 3]};
Now I want to remove the 1s from every array in a that contains 1 so that the output is as shown
a = {[2 3] [5 3 6] [9 3]};
I know the indices of arrays in cell array 'a' which contain 1. This can be done using for loop and a temporary variable, but this is taking a lot of time (I want to perform the operation on a cell array of size something like 1x100000. The one above is just for an example)
I want to know if there is any direct method that can do this quickly.
Pretty much anything is going to be slow with that large of a cell array. You could try to do this with cellfun but it's not necessarily guaranteed to be any faster than a for loop.
a = cellfun(#(x)x(x ~= 1), a, 'UniformOutput', false);
% a{1} =
% 2 3
% a{2} =
% 5 3 6
% a{3} =
% 9 3
As already commented by Suever, because you are using a cell array and it is a dynamic container, you don't have a choice but to iterate through each cell if you want to modify the contents. Just to be self-contained, here is the for loop approach to do things:
for ii = 1 : numel(a)
a{ii} = a{ii}(a{ii} ~= 1);
end
This may be faster as it doesn't undergo the overhead of cellfun. The code above accesses the vector in each cell and extracts out those values that are not equal to 1 and overwrites the corresponding cell with this new vector.
Using your example:
a = {[1 2 3] [5 3 6] [9 1 3]};
We get:
>> format compact; celldisp(a)
a{1} =
2 3
a{2} =
5 3 6
a{3} =
9 3
This example shows how to remove data from individual cells, and how to delete entire cells from a cell array. To run the code in this example, create a 3-by-3 cell array:
C = {1, 2, 3; 4, 5, 6; 7, 8, 9};
Delete the contents of a particular cell by assigning an empty array to the cell, using curly braces for content indexing, {}:
C{2,2} = []
This code returns
C =
[1] [2] [3]
[4] [] [6]
[7] [8] [9]
Delete sets of cells using standard array indexing with smooth parentheses, (). For example, this command
C(2,:) = []
removes the second row of C:
`
C =
[1] [2] [3]
[7] [8] [9]`
Say I have a 3-D matrix a of dimension [X,Y,Z],
a(:,:,1) = [1 2; 3 4];
a(:,:,2) = [5 6; 7 8];
Is there a way to repeat each entry of a, say N times and construct a new matrix, b, of dimension [X, Y, N*Z]? For example, if N=2, to have a matrix b like so,
%repeat first element of 'a' 2ce
b(:,:,1) = [1 2; 3 4];
b(:,:,2) = [1 2; 3 4];
%repeat second element of 'a' 2ce
b(:,:,3) = [5 6; 7 8];
b(:,:,4) = [5 6; 7 8];
Using a nested loop can achieve this of course, for e.g.
%not tested, but should work
b = zeros(X,Y,N*Z);
k=1;
for j=1:Z
for i=1:N
b(:,:,k) = a(:,:,j);
k=k+1;
end
end
But I'll like to know if there's an inbuilt function available for this purpose.
Create an index of the form 1,1,2,2,... (example for N=2) and use it in the third dimension:
b = a(:,:,ceil(1/N:1/N:size(a,3)));
I have n different length cell vectors, call it c{i}, i=1,2,...,n.
I wanna find those c{i} which equal with others, for example:
c{1}=[1 2 3 4 5 6]; c{2}=[1 3 5 7]; c{3}=[2 4 6 8];
c{4}=[1 4 6]; c{5}=[3 7]; c{6}=[2 4 6 8]; c{7}=[1 3 5 7];
I hope I can find [2 4 6 8] and [1 3 5 7] with a simple way instead of using two loops.
Thanks!
You can do it with unique. You need to convert vectors to strings, because unique works with cell arrays of strings but not with cell arrays of numeric vectors. After unique, you can count how many strings (vector) are repeated with histc, and them some indexing lets you retrieve the corresponding vectors:
strcell = cellfun(#(e) num2str(e), c, 'uniformoutput', 0); %// convert to strings
[~, ii, jj] = unique(strcell); %// apply unique. Second and third outputs needed
ind = find(histc(jj,min(jj)-.5:max(jj)+.2)>1); %// which appear more than once
result = c(ii(ind)); %// indexing to obtain corresponding original vectors
What I'm trying to do is obtain results like the snippet below without a loop.
x = [1 2 3 4];
y = [2 3 4];
z=[7 8];
[x'*y]
for k=1:size(z, 2)
z2(:,:,k)=[x'*y]*z(k);
end
z2
Loops may slow down MATLAB, however. How do I approach the task without them?
You can just do this because z is ` vector:
bsxfun(#times, reshape(z, 1, 1, []), [x'*y])
If z was a 2D matrix itself and you wanted to do a matrix multiplication at each level then you would need to use the links I posted in my comment. But because each time you are multiplying by a scalar, you can use #times.
Have a look here. Base on this, you could do as follows:
x = [1 2 3 4];
y = [2 3 4];
z=[7 8];
% replicate [x'*y] into 3D array.
d = repmat([x'*y], [1, 1, numel(z)])
% multiplay by z vector
z2 = bsxfun(#times, d, reshape(z,[1, 1, numel(z)]))