ISMEMBER() modified result desired

8 visualizaciones (últimos 30 días)
dpb
dpb el 19 de En. de 2019
Editada: dpb el 21 de En. de 2019
[lia,locb]=ismember(A,B);
returns the first/last matching location in B of the elements in A that occur in B depending on which optional parameters one chooses. That's fine for many cases, but...
If it is desired to do a 1:1 matching of elements in A to their corresponding mates in B, a modified behavior would be a desirable option if there are repeated elements -- locB could return the next match after the previous for those elements that may not be unique in either array.
This can be done in a loop, of course, by making a search for each element in A in turn, either keeping an indexing variable as to last location for each element previously located or, conversely, marking the location in B with a missing value or somesuch.
That's the problem, the question is --
Is there some function which already does this that I'm not aware of/can't find or a "more cleverer" way to make the match?
  5 comentarios
Jan
Jan el 21 de En. de 2019
What about a small example?
A = [1, 2, 3, 1, 2, 3];
B = [2, 2, 2, 3, 3];
Is the wanted output this:
lia = [0, 1, 1, 0, 1, 1] % as logical
locb = [0, 1, 4, 0, 2, 5]
% ^ ^ would be 1 and 4 for standard ISMEMBER
dpb
dpb el 21 de En. de 2019
Yes, that's the idea...

Iniciar sesión para comentar.

Respuestas (2)

Jan
Jan el 21 de En. de 2019
Editada: Jan el 21 de En. de 2019
Do you mean something like this:
function [lia, locb] = ismemberNext(A, B)
lia = false(size(A));
locb = zeros(size(A));
for iA = 1:numel(A)
match = (A(iA) == B);
if any(match)
lia(iA) = true;
index = find(match, 1);
locb(iA) = index;
B(index) = NaN; % Mask first match for following calls
end
end
end
  2 comentarios
dpb
dpb el 21 de En. de 2019
That's ok w/o the tolerance problem. I'd written (hadn't posted; didn't want to taint the pool first :) )
nG=numel(g); % number of gifts (formula values)
locV=zeros(size(g)); % preallocate lookup location
inV=zeros(size(g)); % preallocate lookup location
vmatch=zeros(size(g)); % matched values cleared
datematch=nat(size(g)); % and the monthy/yr associated
for j=1:nG % find & pair up matching formula values
[inV(j),locV(j)]=ismembertol(g(j),v,'DataScale',0.01);
if inV(j)
vmatch(j)=v(locV(j));
datematch(j)=MT_AU.Date(o(locV(j))); % MMMYY for the formula gift
v(locV(j))=nan;
end
end
vfail=v(isfinite(v)); % retrieve those not matched
The 0.01 tolerance is owing this particular dataset happens to be financial and from a spreadsheet in which there is rounding error in some returned values. One could wrap the find arguments inside a round call.
The datematch array is the corresponding auxiliary "timestamp" variable, v is the dollar value try to match to the g value between two sets of entries that should match but don't always..
It doesn't seem possible to do without the basic loop over the elements in the first and you used the same 'trick' to hide the already found element
The overall problem is a set of entries were made into a number of spreadsheets over a period of a number of years while a corresponding set of comments of which entry correlated to a given one of those entries. The problem is there are a few for which comments weren't entred and/or there were other accounting entries besides new contributions that may have been composite entries that don't match any particular single other entry. For tracking purposes have stripped the entries in the comments (the g array) and the task is to match the known v entries and then isolate the remainder. There's then another independent way with the value and the timestamp to identify which of those is which to finish the task.
dpb
dpb el 21 de En. de 2019
for iA = 1:numel(A)
match = (A(iA) == B);
if any(match)
lia(iA) = true;
index = find(match, 1);
...
Slight optimization, maybe -- may as well just find the location first as have to convert the logical array anyway...
for iA = 1:numel(A)
index = find(A(iA) == B, 1);
if ~isempty(index)
lia(iA) = true;
...

Iniciar sesión para comentar.


Guillaume
Guillaume el 21 de En. de 2019
Maybe I misunderstood the problem, but ismembertol already has the option to return all matching indices in B:
[found, where] = ismembertol(A, B, 'OutputAllIndices', true)
  3 comentarios
Guillaume
Guillaume el 21 de En. de 2019
Are the A that match the same set of B exactly identical? If so, then it's easily solved. If there's a small tolerance on the As as well, then I'll have to think about it.
dpb
dpb el 21 de En. de 2019
Editada: dpb el 21 de En. de 2019
Not necessarily identical, no...I have no way to know a priori which are those elements that contain the rounding discrepancies.
I was considering that I could just go ahead and round the Excel values when read the spreadsheet...that would certainly be faster and probably then makes the need for ismembertol go away...excepting ismember doesn't have the optional output...Catch-22! :)
It seems to me since TMW went this far, there might as well be the 'OutputMatchedIndices' option as well and imo if they're going to add a feature like this to one of the family member functions, it should go in all when it is first introduced, not create yet more uniqueness in interfaces than already exists.
In the end when I'm past the time crunch I'll see about crafting/submitting an enhancment request.
ADDENDUM
On reflection, I guess it would be possible to write
[inA,locB]=ismembertol(round(A,2), round(B,2), 'OutputAllIndices', true);
which _should_ then make the match identical...

Iniciar sesión para comentar.

Categorías

Más información sobre Matrix Indexing en Help Center y File Exchange.

Productos

Community Treasure Hunt

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

Start Hunting!

Translated by