I'm a Perl programmer trying to teach myself Matlab, and having a
hard time getting my brain off its Perl track. I'm facing this
problem: I have a cell array S containing a sequence of symbols
(one symbol per cell). I also have another cell array A containing
the alphabet of the symbols that appear in S. In other words, the
entries in A are unique, and to every symbol in S there corresponds
a unique symbol in A. For example:
S = 'a' 'b' 'r' 'a' 'c' 'a' 'd' 'a' 'b' 'r' 'a'
A = 'a' 'b' 'r' 'c' 'd'
I want to produce a numeric array T obtained by replacing every
entry in S by its position in A. Continuing the example above, T
would be
T = 1 2 3 1 4 1 5 1 2 3 1
In Perl, I would solve this as follows. First, let
@S = ('a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a');
@A = ('a', 'b', 'r', 'c', 'd');
Now, define $a as the length of @A; in Perl:
$a = @A;
Next, define the hash (aka associative array) %d by
@d{@A} = 1..$a;
Now I would get my desired Perl array @T by
for $i (0..$#S) { # $#S is Perl for "the largest index of @S"
$T = $d{$S[$i]};
}
or more slickly by
@T = @d{@S};
Note that this Perl solution is general; in particular the code
would not change if one redefined @A.
What's the "Matlab Way" to achieve the same result in an equally
general way? (I emphasize generality with respect to the definition
of A, because this requirement rules out a solution that relies on
a switch statement.)
Thanks!
b.
[ignore, T] = ismember(S,A)
ignore =
1 1 1 1 1 1 1 1 1 1 1
T =
1 2 3 1 4 1 5 1 2 3 1
Richard
"bill" <bill_k...@yahoo.com> wrote in message
news:bc9ust$sio$1...@reader1.panix.com...
>S = {'a' 'b' 'r' 'a' 'c' 'a' 'd' 'a' 'b' 'r' 'a'};
>A = {'a' 'b' 'r' 'c' 'd'};
>[ignore, T] = ismember(S,A)
> ignore =
> 1 1 1 1 1 1 1 1 1 1 1
>T =
> 1 2 3 1 4 1 5 1 2 3 1
]<ewl!
Thanks!!
b.
>In <bc9vr8$u6f$1...@sabina.mathworks.co.uk> "Richard Lang" <rl...@mathworks.com> writes:
>>S = {'a' 'b' 'r' 'a' 'c' 'a' 'd' 'a' 'b' 'r' 'a'};
>>A = {'a' 'b' 'r' 'c' 'd'};
>>[ignore, T] = ismember(S,A)
>> ignore =
>> 1 1 1 1 1 1 1 1 1 1 1
>>T =
>> 1 2 3 1 4 1 5 1 2 3 1
>]<ewl!
I spoke too soon. When I try the above, I get the error:
>> [ignore, T] = ismember(S,A)
??? Error using ==> ismember
Too many output arguments.
What version of Matlab are you using? I'm using version 6.0.0.88
(R12).
Also, when I read the documentation for ISMEMBER I noticed that
the Matlab version above may be significantly less general than
the Perl version I posted. The Perl version doesn't care whether
@S and @A contain strings or integers or floats, or any mixture of
them; it works correctly in all cases:
@S = ('xyz', 1.23, 1.23, 4.56, 4.56, 4.56, 1.23);
@A = (1.23, 4.56, 'xyz');
@d{@A} = 1..@A;
@T = @d{@S};
@T: 3 1 1 2 2 2 1
Can the Matlab version above handle the case in which A and S are
cell arrays containing numbers and/or strings?
b.
You're right, this capability only exists in R13, Matlab v6.5. Here's
another version that works in v6.1, but it is a bit more convoluted
unfortunately:
[ignore, ignore, idx] = unique([A, S]);
[ignore, idx2] = sort(idx(1:length(A)));
T = idx2(idx(length(A)+1:end))
I don't have an earlier installation to hand but I think I remember these
features being around for a while.
> Also, when I read the documentation for ISMEMBER I noticed that
> the Matlab version above may be significantly less general than
> the Perl version I posted. The Perl version doesn't care whether
> @S and @A contain strings or integers or floats, or any mixture of
> them; it works correctly in all cases:
>
> @S = ('xyz', 1.23, 1.23, 4.56, 4.56, 4.56, 1.23);
> @A = (1.23, 4.56, 'xyz');
>
> @d{@A} = 1..@A;
>
> @T = @d{@S};
>
> @T: 3 1 1 2 2 2 1
>
>
> Can the Matlab version above handle the case in which A and S are
> cell arrays containing numbers and/or strings?
Unfortunately it can't. I can't find anything better than a good old
double-loop:
T = zeros(size(S));
for n = 1:length(S)
for m = 1:length(A)
if isequal(S{n}, A{m})
T(n) = m;
break
end
end
end
Richard