File Exchange

## sub2allind

version 1.5.0.0 (2.69 KB) by
convert subscripts to ALL corresponding indices

Updated 07 Feb 2012

idx = sub2allind(sz, sub1, sub2, sub3, ... )

Like Matlab's sub2ind, sub2allind computes the equivalent linear indices for
given subscripts of an array with size SZ.
Unlike sub2ind, it computes a field of all combinations of
subscripts. So, instead of calling A( 2:3, 1, 4:11) you might
use
linIdx = sub2allind( size(A), 2:3, 1, 4:11 );

and then call A(linIdx) or A(linIdx(:)) or you reshape linIdx the way you need.

This is usefull whenever you want to access a subset of an array and compare it with a differently shaped thing, like

A(linIdx(:)) = A(linIdx(:)) + <1D-Vector>

Using the naked colon operator is allowed to reference an entire dimension:

linIdx = sub2allind( sz, :, sub2 );

### Cite As

Michael Völker (2021). sub2allind (https://www.mathworks.com/matlabcentral/fileexchange/30096-sub2allind), MATLAB Central File Exchange. Retrieved .

Yung-Yeh Chang

I was about to write something similar to this and yet something even better is already here. Great job.

Alexander Stepanov

Very useful, thanks)

Marc

Matt J

"I wonder if it would be best to make that behaviour default, since you could nevertheless use linIdx(:) if you want it to be a vector."

Perhaps, although if other people have downloaded previous versions of the tool, they might have backward compatibility issues.

Michael Völker

Matt, the reshape thing is the easiest, since the indices happen to automatically be in the right shape (plus 1 leading "dummy dimension") before I convert them to a column vector.
I wonder if it would be best to make that behaviour default, since you could nevertheless use linIdx(:) if you want it to be a vector.

Matt J

I like it. It's occurred to me that it will be a good OOP tool for converting the output of the SUBSTRUCT function to a linear index. All the more reason why processing ':' is a good thing. This often comes up in OOP applications where you want to overload SUBSREF or SUBSASGN.

One more tip I had was to enable a syntax
similar to

linIdx=sub2inall('reshape',size(A),2:3,1,4:11)

which would automatically reshape linIdx to be the same shape as A(2:3,1,4:11). That way, A(linIdx) and A(2:3,1,4:11) would produce exactly the same result (in shape as well as in data content).

Michael Völker

(Narf, I meant of course sub2allind(sz,2:3,':'), not A...)

Michael Völker

Jos, your ngrid-approach is very cool. The only reason I still do not use it is that it still may explode the memory and take quite long, if the requested field of indices itself is very large.
If the array has N dimensions, ngrid will produce N new arrays each the size of the requested field of subscripts. However, as bsxfun is a quite young function, the ngrid approach should be much more portable.

To be honest, I hardly remember where I used this function the last time, but I think it was at some point where I later figured out I could use accumarray() instead of whatever I tried before. But what I know for sure is that the default sub2ind-behaviour *always* bugged me, because it is simply not what I'd expect from it.
So the primary reason for me to code this, was that I have this functionality I expect, or at least have a sneak in the source later, when I forgot how it works. :-)

Matt, I like your remark, so I utilize ':' now. The funny thing is, that not only A(sz,2:3,':') works, but A(sz,2:3,:) is okay, too. Somehow, the colon seems to become a string, automagically...

Matt J

You might want to consider allowing ':' inputs as well. For example, if you want the linear index corresponding to
A(2:3,:,4:11) then you would call

linIdx = sub2allind( size(A), 2:3, ':', 4:11 );

Also, perhaps I'm not seeing all of the situations where you intend to use this, however, I tend to think that you'll save yourself both CPU time and memory if instead of linear indexing A, you simply reshape your 1D-Vector .

Jos (10584)

Sure, for large arrays, the logical-find method is a waste of memory, especially if you only need a few indices ...
Another, fast and vectorized, option:

function idx = sub2allind(sz, varargin)
[subix{1:nargin-1}] = ndgrid(varargin{:}) ;
idx = sub2ind(sz,subix{:}) ;

Michael Völker

Oops, nice... :-)

I had the feeling there should be an easier way...

But nevertheless, I usually work with quite large arrays (some 1E8 entries), where your admittedly very nice code causes a waste of RAM and time since an equal-sized array must be actually created.

With sz=[1E3 1E3 1E3], my version needs about 0.000478 seconds, the find-version takes 1.412256 seconds.

Jos (10584)

function idx = sub2allind(sz, varargin)
tf = false(sz) ;
tf(varargin{:}) = true ;
idx = find(tf) ;

##### MATLAB Release Compatibility
Created with R2011a
Compatible with any release
##### Platform Compatibility
Windows macOS Linux