I still think that using arrays in a datastep would be your best solution but, based on the code offered by jh-ti-bw, here is one way that you could do it using a macro: %macro FIND_CLOSEST_VALUE(limOrDedOption,limorDedValue); %let numOptions = %Sysfunc(Countw(&limOrDedOption.,%str( ))); limOrDedSetFlag = 'N'; /* probe of less or equal as the smallest value */ if &limOrDedValue. <= %Scan(&limOrDedOption., 1,%str( )) then do; lwrVal = %Scan(&limOrDedOption., 1,%str( )); uprVal = %Scan(&limOrDedOption., 1,%str( )); limOrDedSetFlag = 'Y'; end; /* probe of equal or greater as the highest value */ else if &limOrDedValue. >= %Scan(&limOrDedOption., -1,%str( )) then do; lwrVal = %Scan(&limOrDedOption., -1,%str( )); uprVal = %Scan(&limOrDedOption., -1,%str( )); limOrDedSetFlag = 'Y'; end; else do; /* the value must be between 2 values or equal a value of the list*/ %do curLimOrDed = 2 %to &numOptions.; if limOrDedSetFlag = 'N' THEN DO; lwrVal =%Scan(&limOrDedOption., %eval(&curLimOrDed. - 1)); uprVal =%Scan(&limOrDedOption., &curLimOrDed.); IF (lwrval <= &limOrDedValue.) and (&limOrDedValue.) <= uprVal THEN limOrDedSetFlag = 'Y'; end; %end; end; if lwrVal eq uprVal then closest=lwrVal; else do; if &limOrDedValue.+(uprVal-lwrVal)/2 gt uprVal then closest=uprVal; else closest=lwrVal; end; drop lwrVal uprVal limOrDedSetFlag; %mend FIND_CLOSEST_VALUE; /* usage */ data test; input testvalue1 testvalue2; cards; 34000 20 249000 24 249999 25 250000 26 250001 30 251000 31 340000 35 1400000 40 2400000 44 ; data want; set test; %FIND_CLOSEST_VALUE(200000 300000 500000 1000000 2000000, testValue1); closest1=closest; %FIND_CLOSEST_VALUE(15 20 22 24 26 28 30 32 34 36 38 41, testValue2); closest2=closest; drop closest; run;
... View more