Substitute a vector value with two values in MATLA

2019-04-09 05:51发布

问题:

I have to create a function that takes as input a vector v and three scalars a, b and c. The function replaces every element of v that is equal to a with a two element array [b,c].

For example, given v = [1,2,3,4] and a = 2, b = 5, c = 5, the output would be:

out = [1,5,5,3,4]

My first attempt was to try this:

v = [1,2,3,4];
v(2) = [5,5];

However, I get an error, so I do not understand how to put two values in the place of one in a vector, i.e. shift all the following values one position to the right so that the new two values fit in the vector and, therefore, the size of the vector will increase in one. In addition, if there are several values of a that exist in v, I'm not sure how to replace them all at once.

How can I do this in MATLAB?

回答1:

Here's a solution using cell arrays:

% remember the indices where a occurs
ind = (v == a);
% split array such that each element of a cell array contains one element
v = mat2cell(v, 1, ones(1, numel(v)));
% replace appropriate cells with two-element array
v(ind) = {[b c]};
% concatenate
v = cell2mat(v);

Like rayryeng's solution, it can replace multiple occurrences of a.

The problem mentioned by siliconwafer, that the array changes size, is here solved by intermediately keeping the partial arrays in cells of a cell array. Converting back to an array concenates these parts.



回答2:

Something I would do is to first find the values of v that are equal to a which we will call ind. Then, create a new output vector that has the output size equal to numel(v) + numel(ind), as we are replacing each value of a that is in v with an additional value, then use indexing to place our new values in.

Assuming that you have created a row vector v, do the following:

%// Find all locations that are equal to a
ind = find(v == a);

%// Allocate output vector
out = zeros(1, numel(v) + numel(ind));

%// Determine locations in output vector that we need to
%// modify to place the value b in
indx = ind + (0:numel(ind)-1);

%// Determine locations in output vector that we need to
%// modify to place the value c in
indy = indx + 1;

%// Place values of b and c into the output
out(indx) = b;
out(indy) = c;

%// Get the rest of the values in v that are not equal to a
%// and place them in their corresponding spots.
rest = true(1,numel(out));
rest([indx,indy]) = false;
out(rest) = v(v ~= a);

The indx and indy statements are rather tricky, but certainly not hard to understand. For each index in v that is equal to a, what happens is that we need to shift the vector over by 1 for each index / location of v that is equal to a. The first value requires that we shift the vector over to the right by 1, then the next value requires that we shift to the right by 1 with respect to the previous shift, which means that we actually need to take the second index and shift by the right by 2 as this is with respect to the original index.

The next value requires that we shift to the right by 1 with respect to the second shift, or shifting to the right by 3 with respect to the original index and so on. These shifts define where we're going to place b. To place c, we simply take the indices generated for placing b and move them over to the right by 1.

What's left is to populate the output vector with those values that are not equal to a. We simply define a logical mask where the indices used to populate the output array have their locations set to false while the rest are set to true. We use this to index into the output and find those locations that are not equal to a to complete the assignment.


Example:

v = [1,2,3,4,5,4,4,5];
a = 4;
b = 10;
c = 11;

Using the above code, we get:

out =

     1     2     3    10    11     5    10    11    10    11     5

This successfully replaces every value that is 4 in v with the tuple of [10,11].



回答3:

I think that strrep deserves a mention here. Although it's called string replacement and warns for non-char input, it still works perfectly fine for other numbers as well (including integers, doubles and even complex numbers).

v = [1,2,3,4] 
a = 2, b = 5, c = 5
out = strrep(v, a, [b c])

Warning: Inputs must be character arrays or cell arrays of strings.
out =
     1     5     5     3     4


回答4:

You are not attempting to overwrite an existing value in the vector. You're attempting to change the size of the vector (meaning the number of rows or columns in the vector) because you're adding an element. This will always result in the vector being reallocated in memory.

Create a new vector, using the first and last half of v.

Let's say your index is stored in the variable index.

index = 2;
newValues = [5, 5];
x = [ v(1:index), newValues,  v(index+1:end) ]

x =

     1     2     5     5     3     4