Dynamically adding elements into an array every nth element based on user-defined inputs, while preserving array order

25 views (last 30 days)
Let's say I have a folder with an object sequence, and I want to copy/paste this object sequence into a new subfolder - but, I also want to insert copies of an arbitrary object into this sequence every nth object, where n is supplied by the user. Additionally, the naming schema has to be updated such that these inserted object stay in place, and we're not inadvertently deleting any objects from the original sequence.
In principal, the problem might look something like this:
OG_Sequence = [ 1 2 3 4 5 6 ] ; % original sequence
insertion_ratio = 2 ; % insert every "#" times
insertion_obj = "X" ; % this is an arbitrary object
New_Sequence = [ 1 2 X 3 4 X 5 6 X ] ; % this is what we want, with everything named in ascending order.
Where length(New_Sequence) = length(Old_Sequence) + length(Old_Sequence)/insertion_ratio. Above is 9, because 6 + 6/2 = 9. You can see how this might change depending on the length of the original (OG) sequence and/or the insertion ratio, e.g.:
OG_Sequence = [ 1 2 3 4 5 6 ] ;
insertion_ratio = 1 ;
insertion_obj = "X" ;
New_Sequence = [ 1 X 2 X 3 X 4 X 5 X 6 X ] ;
or:
OG_Sequence = [ 1 2 3 4 5 6 7 8 9 ] ;
insertion_ratio = 3 ;
insertion_obj = "X" ;
New_Sequence = [ 1 2 3 X 4 5 6 X 7 8 9 X ] ;
I've already got code written to get the user to supply the location of the object sequence, and copy those files over into a new subfolder... but I'm getting mired in edge-cases (how to handle evens/odds, what to do when the insertion_ratio==1, etc.), and above all, how to approach this dynamically and neatly.
So far I've got switch/case statements, as well as mod() statements, but I'm not having any luck in getting the output I want:
New_Sequence(1) = Old_Sequence(1) % Starts with the original, always
switch insertion_ratio
case insertion_ratio == 1 % Edge-case: where ratio = 1
m = 1 ;
for n = 2 : 2 : length(New_Sequence)
New_Sequence(n) = insertion_object ;
end
for n = 3 : 2 : length(New_Sequence)
New_Sequence(n) = Old_Sequence(n - m) ;
m = m + 1 ;
end
otherwise
for n = 2 : length(New_Sequence)
if mod(n, insertion_ratio) == 0
New_Sequence(n) = insertion_obj ;
else
New_Sequence(n) = Old_Sequence(n) ; % ?????????
end
end
end
The above works for the edge-case where the insertion_ratio = 1, but... that's it. I'm kind of stuck on how to move forward. I realize the problem is pretty vague, but that's because I'm trying not to clutter the post more than it already is.
Thanks!

Accepted Answer

Jan
Jan on 27 Feb 2018
Edited: Jan on 27 Feb 2018
data = [ 1 2 3 4 5 6 ] ;
n = 1; % Step width
x = -1; % To insert
len = numel(data);
result = [data; nan(1, len)];
result(2, n:n:len) = x;
result = result(~isnan(result)).';
This appends an additional row with NaNs and inserts the value in the wanted locations. Then the remaining NaNs are removed and the matrix elements are joined to a vector.
result = [data; nan(1, len)];
[1 2 3 4 5 6;
NaN NaN NaN NaN NaN NaN]
result(2, n:n:len) = x;
[1 2 3 4 5 6;
x NaN x NaN x NaN]
Now the NaNs are removed. The logical indexing processes the matrix
in columnwise order.
result(~isnan(result))
[1 x 2 x 3 x 4 x 5 x 6]

More Answers (1)

Andrei Bobrov
Andrei Bobrov on 27 Feb 2018
S = 1:7; % original sequence
ir = 2 ; % insert every "#" times
io = 9999; % io this is an arbitrary object
%New_Sequence = [ 1 2 X 3 4 X 5 6 X ] ;
S = [S(:);nan(mod(-numel(S),ir),1)];
Sn = reshape(S,ir,[]);
Sn = [Sn;repmat(io,1,size(Sn,2))];
out = Sn(~cumsum(isnan(Sn)))
  1 Comment
Jan
Jan on 28 Feb 2018
+1. I thought twice about the meaning of ~cumsum(isnan(x)). I even tried, if this is a typo and cumsum(~isnan(x)) was meant, but then I saw it. Thanks, it is nicer than
1:find(isnan(x(:)), 1, 'first')

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!