find and replace values in cell array - arrays

I have a cell array like this: [...
0
129
8...2...3...4
6...4
0
I just want to find and replace specific values, but I can't use the ordinary function because the cells are different lengths. I need to replace many specific values at the same time and there is no general function about how values are replaced. However, sometimes several input values should be replaced by the same output.
so I want to say
for values 1:129
'if 0, then 9'
'elseif 1 then 50'
'elseif 2 or 3 or 4 then 61'
etc...up to 129
where these rules are applied to the entire array.
I've tried to work it out myself, but still getting nowhere. Please help!

Since your values appear to span the range 0 to 129, one solution is to add one to these values (so they span the range 1 to 130) and use them as indices into a vector of replacement values. Then you can apply this operation to each cell using the function CELLFUN. For example:
>> C = {0, 129, [8 2 3 4], [6 4], 0}; %# The sample cell array you give above
>> replacement = [9 50 61 61 61 100.*ones(1,125)]; %# A 1-by-130 array of
%# replacement values (I
%# added 125 dummy values)
>> C = cellfun(#(v) {replacement(v+1)},C); %# Perform the replacement
>> C{:} %# Display the contents of C
ans =
9
ans =
100
ans =
100 61 61 61
ans =
100 61
ans =
9

Related

How to get the list of indices connecting two 1-d arrays?

Suppose A and B are two 1d arrays of different sizes such that pythonically B = A[C] where C is a particular list of indices meeting some specific but otherwise known condition. How to get C if A and B are both known? I tried C = np.where(np.close(A, B)) but I get the following error message:
File "/home/username/../my_script.py", line 897, in get_histogram
i0, i1 = np.where(np.isclose(hist_xs, vals1)), np.where(np.isclose(hist_ys, vals2))
File "<__array_function__ internals>", line 6, in isclose
File "/usr/local/anaconda3/lib/python3.7/site-packages/numpy/core/numeric.py", line 2260, in isclose
return within_tol(x, y, atol, rtol)
File "/usr/local/anaconda3/lib/python3.7/site-packages/numpy/core/numeric.py", line 2246, in within_tol
return less_equal(abs(x-y), atol + rtol * abs(y))
ValueError: operands could not be broadcast together with shapes (722,) (1536,)
In other words, I am trying to get only those elements of A whose right indices would correspond to the known B array.
Are you looking for this?:
sorti = np.argsort(A)
C_inv = sorti[np.searchsorted(A,B,sorter=sorti)]
sample code (it works on any sortable array, if your array elements do not have comparison operator, you could write your own. If (less/greater) comparison is not applicable, you would need a for loop to find elements which seems to easy to include here):
A: [89 28 86 73 29 71 37 46 15 52]
B: [86 52 15]
C: [2 9 8]
C_inv: [2 9 8]

Fast way to store different length Matrix rows into Cell

I have three matrices:
Values = [200x7] doubles
numOfStrings = [82 78 75 73 72 71 70] %(for example)
numOfColumns = [1 4]
The numOfColumns may contain any set of distinct values from 1 to 7. For example [1 2 3] or [4 7] or [1 5 6 7]. Obviously, biggest numOfColumns that can be is [1 2 3 4 5 6 7].
numOfColumns show the columns I want to get. numOfStrings shows the rows of that columns I need. I.e. in my example I want to get columns 1 and 4. So from the 1 column I want to get the 82 first rows and from the 4th get the 73 first rows.
i.e. if numOfColumns = [1 4] then
myCell{1} = Values( 1:82,1); % Values(numOfStrings(numOfColumn(1)), numOfColumn(1))
myCell{2} = Values( 1:73,4); % Values(numOfStrings(numOfColumn(2)), numOfColumn(2))
P.S. That's not necessary to save it into cell array. If you can offer any another solution Ill be grateful to you.
I'm looking for the fastest way to do this, which is likely to be by avoiding for loops and using vectorization.
I think a lot about sub2ind function. But I can't figure out how to return arrays of the different size! Because myCell{1} - [82x1] and myCell{2} - [73x1]. I suppose I can't use bsxfun or arrayfun.
RESULTS:
Using for loops alike #Will 's answer:
for jj = 1:numel(numOfColumns)
myCell{rowNumber(numOfColumns(jj)),numOfColumns(jj)} = Values( 1:numOfStrings(numOfColumns(jj)),numOfColumns(jj));
end
Elapsed time is 157 seconds
Using arrayfun alike #Yishai E 's answer:
myCell(sub2ind(size(myCell),rowNumber(numOfColumns),numOfColumns)) = arrayfun( #(nOC) Values( 1:numOfStrings(nOC),nOC), numOfColumns, 'UniformOutput', false);
Elapsed time is 179 seconds
Using bsxfun alike #rahnema1 's answer:
idx = bsxfun(#ge,numOfStrings , (1:200).');
extracted_values = Values (idx);
tempCell = mat2cell(extracted_values,numOfStrings);
myCell(sub2ind(size(myCell),rowNumber(numOfColumns),numOfColumns)) = myCell(numOfColumns)';
Elapsed time is 204 seconds
SO, I got a lot of working answers, and some of them are vectorized as I asked, but for loops still fastest!
This should solve your problem, using arrayfun, which "vectorizes" the application of the indexing function. Not really, but it doesn't call the interpreter for each entry from numOfColumns. Interestingly enough, this is slower than the non-vectorized code in the other answer! (for 1e5 entries, 0.95 seconds vs. 0.23 seconds...)
arrayfun(#(nOC)Values(1:numOfStrings(nOC), nOC), numOfColumns, 'UniformOutput', false)
% Get number of elements in NUMOFCOLUMNS
n = numel(numOfColumns);
% Set up output
myCell = cell(1,n);
% Loop through all NUMOFCOLUMNS values, storing to cell
for i = 1:n
myCell{i} = Values(1:numOfStrings(numOfColumns(i)), numOfColumns(i));
end
Which for your example gives output
myCell =
[82x1 double] [73x1 double]
You can create logical indices for extraction of the desired elements :
idx = bsxfun(#ge,numOfStrings , (1:200).');
that in MATLAB R2016b or Octave (thanks to broadcasting/expansion) can be written as:
idx = numOfStrings >= (1:200).';
extract values:
extracted_values = Values (idx);
then using mat2cell convert data to cell :
myCell = mat2cell(extracted_values,numOfStrings);
all in one line :
myCell = mat2cell(Values (numOfStrings >= (1:200).'), numOfStrings);
If you want to use different numOfColumns with different sizes to extract elements of the cell you can each time do this:
result = myCell(numOfColumns);
If both numOfStrings and numOfColumns change and you need to compute the result once do this:
%convert numOfColumns to logical index:
numcols_logical = false(1,7);
numcols_logical(numOfColumns) = true;
extracted_values = Values ((numOfStrings .* numcols_logical) >= (1:200).');
if you need cell array
result= mat2cell(extracted_values,numOfStrings(numcols_logical));

Delete values between specific ranges of indices in an array

I have an array :
Z = [1 24 3 4 52 66 77 8 21 100 101 120 155];
I have another array:
deletevaluesatindex=[1 3; 6 7;10 12]
I want to delete the values in array Z at indices (1 to 3, 6 to 7, 10 to 12) represented in the array deletevaluesatindex
So the result of Z is:
Z=[4 52 8 21 155];
I tried to use the expression below, but it does not work:
X([deletevaluesatindex])=[]
Another solution using bsxfun and cumsum:
%// create index matrix
idx = bsxfun(#plus , deletevaluesatindex.', [0; 1])
%// create mask
mask = zeros(numel(Z),1);
mask(idx(:)) = (-1).^(0:numel(idx)-1)
%// extract unmasked elements
out = Z(~cumsum(mask))
out = 4 52 8 21 155
This will do it:
rdvi= size(deletevaluesatindex,1); %finding rows of 'deletevaluesatindex'
temp = cell(1,rdvi); %Pre-allocation
for i=1:rdvi
%making a cell array of elements to be removed
temp(i)={deletevaluesatindex(i,1):deletevaluesatindex(i,2)};
end
temp = cell2mat(temp); %Now temp array contains the elements to be removed
Z(temp)=[] % Removing the elements
If you control how deletevaluesatindex is generated, you can instead directly generate the ranges using MATLAB's colon operator and concatenate them together using
deletevaluesatindex=[1:3 6:7 10:12]
then use the expression you suggested
Z([deletevaluesatindex])=[]
If you have to use deletevaluesatindex as it is given, you can generate the concatenated range using a loop or something like this
lo = deletevaluseatindex(:,1)
up = deletevaluseatindex(:,2)
x = cumsum(accumarray(cumsum([1;up(:)-lo(:)+1]),[lo(:);0]-[0;up(:)]-1)+1);
deleteat = x(1:end-1)
Edit: as in comments noted this solution only works in GNU Octave
with bsxfun this is possible:
Z=[1 24 3 4 52 66 77 8 21 100 101 120 155];
deletevaluesatindex = [1 3; 6 7;10 12];
idx = 1:size(deletevaluesatindex ,1);
idx_rm=bsxfun(#(A,B) (A(B):deletevaluesatindex (B,2))',deletevaluesatindex (:,1),idx);
Z(idx_rm(idx_rm ~= 0))=[]

Storing blocks of vector data into an array in Matlab

I have an array in Matlab
A = [1 2 3 4 5 6 7 8 9;
67 67 67 86 86 86 86 67 67]';
where every point in the first row of A corresponds to a "code" either 67 or 86. I am trying to extract these blocks of "67s" and "86s" such that every time a block starts the corresponding elements are put into the 3rd dimension of a different array called X, where the .
So for e.g. in A I have 3 different blocks, so I would like to end up with an array X of size 1x9x3. And for e.g. the first 67 block I would like to have X
X(1,:,1) = [1 2 3];
I understand that I would "fill up" this vector X using a for loop
for i=1:size(A,2)
for j=1:size(A,2) %actually j should be up till the number of blocks present
X(1,i,j) = A(1,i)
end
end
But this isn't correct or complete of course because firstly I'm unsure how to separate out the "blocks" and how to correctly "fill in" the j's in X(1,i,j). Secondly how can I get the code to recognise how many blocks there are?
Can anyone help?
Thanks
One possible approach, based on this answer:
>> B = accumarray([0; cumsum(diff(A(:,2)) ~= 0)] + 1, A(:,1), [], #(x) {x}, [])
Now you have this:
>> B{1}
ans =
1
2
3
>> B{2}
ans =
4
5
6
7
>> B{3}
ans =
8
9

Select range based on contents of an array

I have two arrays. I'd like to copy ranges of data from one of them, based on a list of array locations stored in the other. For example, if the first array were comprised of 100 rows and 2 columns, I might like to copy rows 10-20, rows 60-70 and rows 75-79. If that were the case, then the contents of the second array would be as follows:
b =
10 20
60 70
75 79
In order to select the appropriate rows of the first array based on the second (let's call it 'a'), I would do the following:
b = [a(1,1):a(1,2) a(2,1):a(2,2) a(3,1):a(3,2)]
This works, and returns array 'b' which is basically array 'a' with the correct contents extracted.
The problem is, array 'b' actually contains between 50 and 60 rows (i.e ranges to be included).
How do I make the above code more efficient, such that it works for any number of rows in 'b'?
Example:
a = rand(100,1);
ranges = [
10 20
60 70
75 79
];
idx = arrayfun(#colon, ranges(:,1), ranges(:,2), 'Uniform',false);
idx = [idx{:}];
b = a(idx)
You could use a for, assuming ranges of values to be extracted from a are in b, and should go to c:
% input
a = rand(100,2);
b = [10 20; 60 70; 75 79];
% output
c = zeros(1,2);
for i = 1:size(b,1)
c = vertcat(c a(b(i,1):b(i,2), :));
end
c = c(2:size(c,1), :);
A solution using cellfun and cell arrays:
% Some example data:
a = reshape(1:100, 10, 10);
b = [ 2 3; 5 8; 10 10 ];
Here's the code:
bCell = mat2cell(b, 3, [ 1 1 ]);
aRows = cell2mat(arrayfun(#(x,y) a(x:y, :), bCell{1}, bCell{2}, 'UniformOutput', false));

Resources