Loren on the Art of MATLAB

Turn ideas into MATLAB

Repeated Indexing in MATLAB

Indexing is apopular topicI write about from time to time. Today I want to focus on what happens when there are duplicate indices.

Contents

Accessing Array Elements with Repeated Indices

Suppose I want to makenumdupscopies of the elements in odd locations in a vector,vec.

vec = [-40; exp(1); pi; 17; 42]; numdups = 3; oddlocs = 1:2:length(vec); locs = oddlocs(ones(1,numdups),:); locs = locs(:) newvec = vec(locs(:))
locs = 1 1 1 3 3 3 5 5 5 newvec = -40.0000 -40.0000 -40.0000 3.1416 3.1416 3.1416 42.0000 42.0000 42.0000

As you can see, since I requested some repeated values, MATLAB returned them to me.

Just in case you need some clarification, let me explain what's going on here. After creating my array and identifying the location of values I wish to repeat (oddlocs), I reshape this array into a column vectorlocs, and use this array, with its repeated values, to index into the rows I requested, including all the columns (but there is only 1 column here).

Here's an even simpler example that I will extend further.

subs = [1; 3; 3]; newvec = vec(subs)
newvec = -40.0000 3.1416 3.1416

I create my indices - and you can see that I want the first element followed by the 3rd one twice. Let's start with the right-hand side. From a semantic, or meaning, point of view, MATLAB creates a new temporary array extracting the pieces ofvecrequested. Following that, the values in the temporary array are assigned to the outputnewvec.

Here's how you can create a matrix from replicated columns. First by indexing,

threecols = vec(:,[1 1 1])% or vec(:, ones(1,numdups)
threecols = -40.0000 -40.0000 -40.0000 2.7183 2.7183 2.7183 3.1416 3.1416 3.1416 17.0000 17.0000 17.0000 42.0000 42.0000 42.0000

by matrix multiplication

threecols = vec * [1 1 1]% or vec * ones(1,numdups)
threecols = -40.0000 -40.0000 -40.0000 2.7183 2.7183 2.7183 3.1416 3.1416 3.1416 17.0000 17.0000 17.0000 42.0000 42.0000 42.0000

andrepmat.

threecols = repmat(vec,1,3)
threecols = -40.0000 -40.0000 -40.0000 2.7183 2.7183 2.7183 3.1416 3.1416 3.1416 17.0000 17.0000 17.0000 42.0000 42.0000 42.0000

You may also be interested inrepelem.

Please note that you often do not need any of these techniques for certain computations that can be efficiently accomplished with the olderbsxfun, and, more recently, the, in my opinion elegant, implicit expansion behavior (1,2) that you can use to "expand" singleton dimensions.

Replicated Elements for Assignment to Output

Now let's see what we need to do if we have repeated indices in an assignment.

newvec = vec; newvec(subs) = vec(subs) + 10
newvec = -30.0000 2.7183 13.1416 17.0000 42.0000

What you see here is element 1 growing by 10 and same for element 3. However, we have repeated the element 3 index. So the computed right-hand side has element 1 and 2 copies of the updated element 3 - updated each in the same way, since that's what the code says to do. Remember I said that the MATLAB behavior is as if we placed the right-hand side into a temporary array. Once we have finished computing the right-hand side, MATLAB works on the assignment. Head top to bottom (even for multidimensional arrays, since MATLAB stores the data in a column-major format), and it replaces element 1 with a new value, element 3 with a new value, and then does the latter one more time. No extra accumulation of 10s for element 3. But maybe you wanted to accumulate the results for repeated elements, but it's not so tidy that you can simply use something likecumsum.

How to Achieve Accumulation Behavior

You may now that you can create and usesparsematrices in MATLAB. Fromthe doc, you can see that you can accumulate values when constructing a sparse matrix. This has been so handy that eventually we made an analogous function,accumarrayfor non-sparse arrays as well.

一个例子的时候了。我要计算的东西ike vec(subs) = vec(subs) + 10 with the difference being that I want repeated indices to accumulate the number of 10s represented by the repeated indices.

vec = (1:5)' subs = [1; 3; 3];
vec = 1 2 3 4 5

Here's the right-hand side as above.

vec(subs)
ans = 1 3 3
[uniquevals,~,idxUnique] = unique(subs)
uniquevals = 1 3 idxUnique = 1 2 2

Notice that I call the functionuniqueand retrieve the third output, the actual locations of the unique indices as they appear in the output.

vec(uniquevals) = vec(uniquevals) + accumarray(idxUnique, 10)
vec = 11 2 23 4 5

Finally let me return to the initial vector from the beginning of the post. I'm guessing you fully understand what's happening here now.

subs = [1; 3; 3]; vec = [-40; exp(1); pi; 17; 42]; newvec = vec; [uniquesubs,~,idxUnique] = unique(subs); newvec(uniquesubs) = vec(uniquesubs) + accumarray(idxUnique, 10)
newvec = -30.0000 2.7183 23.1416 17.0000 42.0000

What Are Your Indexing Challenges When Handling Repeated Indices?

想知道你是否有一些挑战不是湾red here when dealing with repeated indices. Let me knowhere.




Published with MATLAB® R2019b

|
  • print
  • send email

Comments

To leave a comment, please clickhereto sign in to your MathWorks Account or create a new one.