Match - Replace values in one list with closest values in a second list. USAGE [matched,only1,only2] = Match(list1,list2,<options>) list1 first list list2 second list <options> optional list of property-value pairs (see table below) ========================================================================= Properties Values ------------------------------------------------------------------------- 'match' optional matching criterion: 'up', 'down' (default) or 'closest' (see below) 'error' matched values for which the difference exceeds this threshold are set to NaN (default = inf) ========================================================================= OUTPUT matched values in list2 that matched those of list1 only1 elements in list1 that were not matched by any element in list2 only2 elements in list2 that did not match any element in list1 only1 and only2 are lists of logical indices. NOTE Pairs are matched in the following way. Assume the lists are sorted in ascending order and let list1 = [a(1)...a(n)] and list2 = [b(1)...b(m)]. We are trying to match each a(i) with one of the b(1..m). Suppose b(1) <= ... <= b(j) <= a(i) <= b(j+1) <= ... <= b(m) Then a(i) will be matched with either b(j) or b(j+1), depending on the 'match' option: 1) 'down' (default) => b(j) 2) 'up' => b(j+1) 3) 'closest' => the one that minimizes the distance (b(j) if the distances are equal) If however the distance between a(i) and b(j) (or b(j+1)) is too large (see option 'error'), then none of the b(1..m) matches a(i). Note that this function is generally asymmetrical.
0001 function [matched,only1,only2] = Match(list1,list2,varargin) 0002 0003 %Match - Replace values in one list with closest values in a second list. 0004 % 0005 % USAGE 0006 % 0007 % [matched,only1,only2] = Match(list1,list2,<options>) 0008 % 0009 % list1 first list 0010 % list2 second list 0011 % <options> optional list of property-value pairs (see table below) 0012 % 0013 % ========================================================================= 0014 % Properties Values 0015 % ------------------------------------------------------------------------- 0016 % 'match' optional matching criterion: 'up', 'down' (default) or 0017 % 'closest' (see below) 0018 % 'error' matched values for which the difference exceeds this 0019 % threshold are set to NaN (default = inf) 0020 % ========================================================================= 0021 % 0022 % OUTPUT 0023 % 0024 % matched values in list2 that matched those of list1 0025 % only1 elements in list1 that were not matched by any element in list2 0026 % only2 elements in list2 that did not match any element in list1 0027 % 0028 % only1 and only2 are lists of logical indices. 0029 % 0030 % NOTE 0031 % 0032 % Pairs are matched in the following way. Assume the lists are sorted in 0033 % ascending order and let list1 = [a(1)...a(n)] and list2 = [b(1)...b(m)]. 0034 % We are trying to match each a(i) with one of the b(1..m). Suppose 0035 % 0036 % b(1) <= ... <= b(j) <= a(i) <= b(j+1) <= ... <= b(m) 0037 % 0038 % Then a(i) will be matched with either b(j) or b(j+1), depending on the 0039 % 'match' option: 0040 % 0041 % 1) 'down' (default) => b(j) 0042 % 2) 'up' => b(j+1) 0043 % 3) 'closest' => the one that minimizes the distance 0044 % (b(j) if the distances are equal) 0045 % 0046 % If however the distance between a(i) and b(j) (or b(j+1)) is too large 0047 % (see option 'error'), then none of the b(1..m) matches a(i). 0048 % 0049 % Note that this function is generally asymmetrical. 0050 0051 % Copyright (C) 2004-2012 by Michaƫl Zugaro 0052 % 0053 % This program is free software; you can redistribute it and/or modify 0054 % it under the terms of the GNU General Public License as published by 0055 % the Free Software Foundation; either version 3 of the License, or 0056 % (at your option) any later version. 0057 0058 % Default values 0059 match = 'down'; 0060 err = inf; 0061 0062 % Check parameters 0063 if nargin < 2 | mod(length(varargin),2) ~= 0, 0064 error('Incorrect number of parameters (type ''help <a href="matlab:help Match">Match</a>'' for details).'); 0065 end 0066 if ~isdvector(list1) | ~isdvector(list2), 0067 error('Incorrect sizes: ''list1'' and ''list2'' must be vectors (type ''help <a href="matlab:help Match">Match</a>'' for details).'); 0068 end 0069 0070 % Parse parameter list 0071 for i = 1:2:length(varargin), 0072 if ~isa(varargin{i},'char'), 0073 error(['Parameter ' num2str(i+2) ' is not a property (type ''help <a href="matlab:help Match">Match</a>'' for details).']); 0074 end 0075 switch(lower(varargin{i})), 0076 0077 case 'match', 0078 match = lower(varargin{i+1}); 0079 if ~isastring(match,'up','down','closest'), 0080 error('Incorrect value for property ''match'' (type ''help <a href="matlab:help Match">Match</a>'' for details).'); 0081 end 0082 0083 case 'error', 0084 err = varargin{i+1}; 0085 if ~isdscalar(err,'>=0'), 0086 error('Incorrect value for property ''error'' (type ''help <a href="matlab:help Match">Match</a>'' for details).'); 0087 end 0088 0089 otherwise, 0090 error(['Unknown property ''' num2str(varargin{i}) ''' (type ''help <a href="matlab:help Match">Match</a>'' for details).']); 0091 0092 end 0093 end 0094 0095 % Sort elements in both list so that list1 = [a1 a2 a3 ... an] and list2 = [b1 b2 b3 ... bm] 0096 [list1,idx1] = sort(list1(:)); 0097 [list2,idx2] = sort(list2(:)); 0098 0099 % Find 'up' and 'down' matching indices 0100 % (We need both, because this will allow us to compare matches if the criterion is 'closest') 0101 n = length(list2); 0102 up = MatchUpIndices(list1,list2); 0103 down = up-1; 0104 0105 % List corresponding values in list2 0106 % Special cases: when matching down (resp. up), values in list1 lesser (resp. greater) 0107 % than all values in list2 cannot be matched; set them to NaN 0108 goodUp = up>0 & up<=n; 0109 matchedUp = nan(size(up)); 0110 matchedUp(goodUp) = list2(up(goodUp)); 0111 goodDown = down>0 & down<=n; 0112 matchedDown = nan(size(down)); 0113 matchedDown(goodDown) = list2(down(goodDown)); 0114 0115 % Use match criterion 0116 switch(match), 0117 case 'up', 0118 matched = matchedUp; 0119 case 'down', 0120 matched = matchedDown; 0121 case 'closest', 0122 [~,idx] = min(abs([matchedUp matchedDown]-[list1 list1]),[],2); 0123 matched = matchedUp; 0124 matched(idx==2) = matchedDown(idx==2); 0125 end 0126 0127 % Check error threshold 0128 bad = abs(matched-list1) > err+eps; % eps is to compensate for inevitable numerical rounding errors such as 1.1-1.0>0.1 0129 matched(bad) = nan; 0130 0131 % Output 0132 only1 = isnan(matched); 0133 matched = matched(~only1); 0134 only1(idx1) = only1; 0135 only2 = logical(zeros(size(list2))); 0136 m = unique(matched); 0137 [~,i] = setdiff(list2,m); 0138 only2(i) = 1; 0139 only2(idx2) = only2; 0140