How to change a sequence of integers?

7 views (last 30 days)
S H
S H on 4 Mar 2021
Commented: S H on 5 Mar 2021
I am new to Matlab and coming up already with a tricky question. Suppose a sequence of integers
[2 1 3 4 1 1 3 1 2 1 2 2 5 3 2];
that I want to change according to the following rules:
  • When there is a one not followed or preceeded by another one, I want to replace the one, the preceeding and following number by the sum of the two numbers around the one.
  • If for two given ones, the preceeding and following numbers overlap, I want to add them allogether.
So in my example, I should obtain:
[5 5 5 4 1 1 7 7 7 7 7 2 5 3 2]
The first three numbers turn to be 5 because I add 2 + 3, according to rule 1. The next three numbers 4 1 1 remain unchanged, also according to rule 1. The then coming 5 numbers [3 1 2 1 2] should all be added together, because of rule 2. Lastly, 2 5 3 2 remain unchanged.
I cannot figure out how to do this. Perhaps there is a way of writing a recursive function that picks a one, checks if and how much numbers have to be added from the left and then looks at the right and finally sums the numbers up. Does anyone have a clue? Many thanks in advance
  3 Comments
S H
S H on 4 Mar 2021
Yes it's all but the ones. [2,1,3,1,4,1,5] should give [14,14,14,14,14,14,14].
Jan
Jan on 4 Mar 2021
Okay. So I assume you want sequences of [a,1,b,1,c,1,d,...] of any length to be considered.

Sign in to comment.

Accepted Answer

Jan
Jan on 4 Mar 2021
Edited: Jan on 4 Mar 2021
Rule 1 is easy:
x = [2 1 3 4 1 1 3 1 2 1 2 2 5 3 2];
m = strfind(x == 1, [false, true, false]);
y = x;
xm = x(m) + x(m+2);
y(m) = xm;
y(m+1) = xm;
y(m+2) = xm;
To find a similar approach for rule 2 we need a unique definition at first. See my comment above. Are the elements, which are not 1 always greater than 1 or does the input contain negative values and zeros also?
If there are not sequences with more than 2 ones surrounded by non-ones, the above approach can be expanded and run at first:
m = strfind(x == 1, [false, true, false, true, false]);
xm = x(m) + x(m+2) + x(m+4);
... etc.
[EDITED] Including rule 2:
x = [2 1 3 4 1 1 3 1 2 1 2 2 5 3 2 2,1,3,1,4,1,5];
m = strfind(x == 1, [false, true, false]); % Search for [a,1,b]
p = false(1, numel(x) + 2); % Mask [a,b,1,c,d] as
p(m+1) = true; % [false, true, true, true, false]
p(m+2) = true;
p(m+3) = true;
% x: 2 1 3 4 1 1 3 1 2 1 2 2 5 3 2 2 1 3 1 4 1 5
% p: 0 1 1 1 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 0
% ^ to detect initial [0 1] and final [1 0] ^
ini = strfind(p, [false, true]); % Search for starts and ends of blocks
fin = strfind(p, [true, false]) - 1;
for k = 1:numel(ini) % Loop over sequences
rep = sum(x(ini(k):2:fin(k))); % Sum values surrounding the 1s
x(ini(k):fin(k)) = rep; % Replace elements
end
% Check:
isequal(x, ...
[5 5 5 4 1 1 7 7 7 7 7 2 5 3 2 14 14 14 14 14 14 14])
  3 Comments
Jan
Jan on 4 Mar 2021
Edited: Jan on 4 Mar 2021
You are welcome. Do you see the idea: Mask the pattern and search for initial and final points. This is much easier than running a loop over the original elements and searching for the limits of the sequences:
% NOT EXHAUSTIVELY TESTED!!!
x = [2 1 3 4 1 1 3 1 2 1 2 2 5 3 2 2,1,3,1,4,1,5];
nx = numel(x);
accum = 0;
ix = 2;
while ix < nx % Not <= !
if x(ix) == 1
if x(ix - 1) ~= 1 && x(ix + 1) ~= 1
fin = ix + 1; % End point
if accum == 0 % Initial point found
ini = ix - 1; % Remember start point
accum = x(ini) + x(fin);
else % Ongoing sequence
accum = accum + x(fin);
end
ix = ix + 1; % Proceed 1 additional element
end
elseif accum ~= 0 % Flush accumulator
x(ini:fin) = accum;
accum = 0; % Reset accumulator
end
ix = ix + 1; % Proceed to next element
end
if accum ~= 0 % Flush final accumulator on demand:
x(ini:fin) = accum;
end
This loop looks like a typical C approach, while the vectorized method above is "matlabish".
S H
S H on 5 Mar 2021
This is a clever way, too. Thank you!

Sign in to comment.

More Answers (0)

Tags

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!