1

In Matlab, I have an array that has labels, for example

Events = [10; 11; 41; 42; 31; 32; 41; 42]; 

I want to edit this array so that after each 41 I insert 8 411s such that I end up with:

New_events = [10; 11; 41; 411; 411; 411; 411; 411; 411; 411; 411; 42; 31; 
              32; 41; 411; 411; 411; 411; 411; 411; 411; 411; 42];

Is there a simple way to do this?

I have used find to get the indices of each occurrence of 41 but am unsure how to preserve the order of the other labels... Does anyone know how I could do this?

I have just posted a small example of the what the array looks like but in reality, it is much bigger and I need to do this many times (appx 200 times) so I need something automated...

Thanks

Maheen Siddiqui
  • 539
  • 8
  • 19

3 Answers3

1

Find all 41, and iterate over them. Just, after each insertion, add 8 to the next index of 41:

finds_41 = find(Events == 41).';
counter = 0;
for idx = finds_41
    pos_41 = idx + counter*8
    Events = [Events(1:pos_41); 411 * ones(8,1); Events((pos_41 + 1):end)];
    counter = counter + 1;
end
OmG
  • 18,337
  • 10
  • 57
  • 90
  • Thanks for the answer but this only adds 411 to the first 41 it finds, the rest stay as they are – Maheen Siddiqui Jun 22 '18 at 15:07
  • @MaheenSiddiqui Corrected. Try again. – OmG Jun 22 '18 at 15:11
  • @OmG: It looks a lot nicer than my version! I hoped that was possible. However it is 2200x slower when I compare them with `Events = randi(100,[1E6,1]);`. Probably because you keep copying the events variable. – Gelliant Jun 22 '18 at 15:16
1

You can do this by creating a Boolean for each insertion point (Events==41) then using repmat to repeat 411 either 8 or 0 times.

Then arrayfun makes the code pretty short

Events = [10; 11; 41; 42; 31; 32; 41; 42];
out = arrayfun( @(x,b) [x; repmat(411, 8*b, 1)], Events, Events == 41, 'uni', 0 );
out = vertcat(out{:});
Wolfie
  • 27,562
  • 7
  • 28
  • 55
  • Thanks! In the end, I realized that the array I have is a cell with characters. I modified your code to use strcmp to compare "41" with Events. It works but the only problem is that instead of adding "411" in a new cell each time, there is one cell with 8 "411"s in them... is there someway to overcome that? – Maheen Siddiqui Jun 22 '18 at 16:08
  • You should use `repmat( {'text'}, 8*b, 1)` to create an 8 element cell array from one string. You also might need to use `cellfun` if you have a cell and not an array. – Wolfie Jun 22 '18 at 16:11
  • Hi Wolfie, following on from this question I had another query which I posted here: would you be able to help? https://stackoverflow.com/questions/51009288/repeat-elements-of-an-array-at-specific-locations-matlab-arrayfun – Maheen Siddiqui Jun 24 '18 at 11:12
0

This might work. But I sort of hope there is a simpeler solution to this problem. What you want to do seems so simple.

clear all
Events = [10; 11; 41; 42; 31; 32; 41; 42];
Insert = [411; 411; 411; 411; 411; 411; 411; 411];
atval = 41;

Nin=numel(Insert);
idx = [0;find(Events==atval)];
out = nan(length(Events)+Nin*(length(idx)-1),1);
for ct = 2:length(idx)
    out(Nin*(ct-2)+[1+idx(ct-1):idx(ct)])=Events(1+idx(ct-1):idx(ct)); %copy events
    out(Nin*(ct-2)+idx(ct)+1:Nin*(ct-2)+idx(ct)+Nin)=Insert; %put insert
end
out(Nin*(ct-1)+[1+idx(ct):length(Events)])=Events(1+idx(ct):end); %copy last events
Gelliant
  • 1,835
  • 1
  • 11
  • 23
  • Thanks! This works... I am just trying to make sure I understand what each step is doing – Maheen Siddiqui Jun 22 '18 at 15:07
  • You're welcome. I'm surprised by how fast it is. If you replace the `Events = [...]` with `Events = randi(100,[1E6,1]);` it still runs in 25 ms on my PC. – Gelliant Jun 22 '18 at 15:09
  • Thanks... I have another question... If events was a character array, how would I modify this? I can use strcmp to compare atval? – Maheen Siddiqui Jun 22 '18 at 15:45
  • You could just as well compare a character array with a single character. `find('abcde'=='d')` – Gelliant Jun 22 '18 at 15:56