Getting the IN operator to FUNCTION inside a SAS Macro



Similar documents
Nine Steps to Get Started using SAS Macros

Macro Quoting. Overview of Macro Quoting CHAPTER 7

AN INTRODUCTION TO MACRO VARIABLES AND MACRO PROGRAMS Mike S. Zdeb, New York State Department of Health

Paper An Introduction to SAS PROC SQL Timothy J Harrington, Venturi Partners Consulting, Waukegan, Illinois

Writing cleaner and more powerful SAS code using macros. Patrick Breheny

Search and Replace in SAS Data Sets thru GUI

You have got SASMAIL!

Name: Class: Date: 9. The compiler ignores all comments they are there strictly for the convenience of anyone reading the program.

More Tales from the Help Desk: Solutions for Simple SAS Mistakes Bruce Gilsen, Federal Reserve Board

OBJECT_EXIST: A Macro to Check if a Specified Object Exists Jim Johnson, Independent Consultant, North Wales, PA

JavaScript: Introduction to Scripting Pearson Education, Inc. All rights reserved.

Tales from the Help Desk 3: More Solutions for Simple SAS Mistakes Bruce Gilsen, Federal Reserve Board

Chapter 5 Programming Statements. Chapter Table of Contents

Keywords are identifiers having predefined meanings in C programming language. The list of keywords used in standard C are : unsigned void

PL / SQL Basics. Chapter 3

A Closer Look at PROC SQL s FEEDBACK Option Kenneth W. Borowiak, PPD, Inc., Morrisville, NC

Moving from CS 61A Scheme to CS 61B Java

Counting the Ways to Count in SAS. Imelda C. Go, South Carolina Department of Education, Columbia, SC

Debugging Complex Macros

New Tricks for an Old Tool: Using Custom Formats for Data Validation and Program Efficiency

Translating to Java. Translation. Input. Many Level Translations. read, get, input, ask, request. Requirements Design Algorithm Java Machine Language

Paper Creating Variables: Traps and Pitfalls Olena Galligan, Clinops LLC, San Francisco, CA

Using Macros to Automate SAS Processing Kari Richardson, SAS Institute, Cary, NC Eric Rossland, SAS Institute, Dallas, TX

Let the CAT Out of the Bag: String Concatenation in SAS 9 Joshua Horstman, Nested Loop Consulting, Indianapolis, IN

The SAS Data step/macro Interface

Information and Computer Science Department ICS 324 Database Systems Lab#11 SQL-Basic Query

9.1 SAS. SQL Query Window. User s Guide

The Power of CALL SYMPUT DATA Step Interface by Examples Yunchao (Susan) Tian, Social & Scientific Systems, Inc., Silver Spring, MD

First Java Programs. V. Paúl Pauca. CSC 111D Fall, Department of Computer Science Wake Forest University. Introduction to Computer Science

Limitation of Liability

MATLAB Programming. Problem 1: Sequential

Lecture 2 Notes: Flow of Control

Labels, Labels, and More Labels Stephanie R. Thompson, Rochester Institute of Technology, Rochester, NY

Essential Project Management Reports in Clinical Development Nalin Tikoo, BioMarin Pharmaceutical Inc., Novato, CA

Chapter 2: Elements of Java

Database Programming with PL/SQL: Learning Objectives

Macros from Beginning to Mend A Simple and Practical Approach to the SAS Macro Facility

Computer Programming C++ Classes and Objects 15 th Lecture

SENDING S IN SAS TO FACILITATE CLINICAL TRIAL. Frank Fan, Clinovo, Sunnyvale CA

How to Reduce the Disk Space Required by a SAS Data Set

That Mysterious Colon (:) Haiping Luo, Dept. of Veterans Affairs, Washington, DC

Innovative Techniques and Tools to Detect Data Quality Problems

13 Classes & Objects with Constructors/Destructors

Chapter One Introduction to Programming

AN INTRODUCTION TO THE SQL PROCEDURE Chris Yindra, C. Y. Associates

Introduction to Java Applications Pearson Education, Inc. All rights reserved.

From The Little SAS Book, Fifth Edition. Full book available for purchase here.

ESCI 386 IDL Programming for Advanced Earth Science Applications Lesson 6 Program Control

Retrieving Data from Large DB2 Tables Based on Keys in SAS : The Sequel

EXST SAS Lab Lab #4: Data input and dataset modifications

Bachelors of Computer Application Programming Principle & Algorithm (BCA-S102T)

Writing Control Structures

ABSTRACT INTRODUCTION %CODE MACRO DEFINITION

Retrieving Data Using the SQL SELECT Statement. Copyright 2006, Oracle. All rights reserved.

Table Lookups: From IF-THEN to Key-Indexing

3.GETTING STARTED WITH ORACLE8i

SAS PROGRAM EFFICIENCY FOR BEGINNERS. Bruce Gilsen, Federal Reserve Board

Quick Start to Data Analysis with SAS Table of Contents. Chapter 1 Introduction 1. Chapter 2 SAS Programming Concepts 7

Introduction to Python

Perl in a nutshell. First CGI Script and Perl. Creating a Link to a Script. print Function. Parsing Data 4/27/2009. First CGI Script and Perl

Systems Programming & Scripting

Bash shell programming Part II Control statements

Visual Basic Programming. An Introduction

SAS Macro Programming for Beginners

A Method for Cleaning Clinical Trial Analysis Data Sets

The SET Statement and Beyond: Uses and Abuses of the SET Statement. S. David Riba, JADE Tech, Inc., Clearwater, FL

PharmaSUG 2014 Paper CC23. Need to Review or Deliver Outputs on a Rolling Basis? Just Apply the Filter! Tom Santopoli, Accenture, Berwyn, PA

WESTMORELAND COUNTY PUBLIC SCHOOLS Integrated Instructional Pacing Guide and Checklist Computer Math

PharmaSUG Paper QT26

MULTIPLE CHOICE. Choose the one alternative that best completes the statement or answers the question.

VB.NET Programming Fundamentals

Differences in Use between Calc and Excel

SAS Macro Autocall and %Include

KEYWORDS ARRAY statement, DO loop, temporary arrays, MERGE statement, Hash Objects, Big Data, Brute force Techniques, PROC PHREG

DTD Tutorial. About the tutorial. Tutorial

THE POWER OF PROC FORMAT

Shell Scripts (1) For example: #!/bin/sh If they do not, the user's current shell will be used. Any Unix command can go in a shell script

Managing Tables in Microsoft SQL Server using SAS

Storing and Using a List of Values in a Macro Variable

Advanced Tutorials. Numeric Data In SAS : Guidelines for Storage and Display Paul Gorrell, Social & Scientific Systems, Inc., Silver Spring, MD

Object-Oriented Design Lecture 4 CSU 370 Fall 2007 (Pucella) Tuesday, Sep 18, 2007

C++ INTERVIEW QUESTIONS

Oracle Database: SQL and PL/SQL Fundamentals

J a v a Quiz (Unit 3, Test 0 Practice)

Unix Scripts and Job Scheduling

SAS ODS HTML + PROC Report = Fantastic Output Girish K. Narayandas, OptumInsight, Eden Prairie, MN

This module explains fundamental aspects of Microsoft Dynamics NAV Development Environment.

Informatica e Sistemi in Tempo Reale

Xerox Standard Accounting Import/Export User Information Customer Tip

Oracle Database: SQL and PL/SQL Fundamentals

Post Processing Macro in Clinical Data Reporting Niraj J. Pandya

Importing Excel Files Into SAS Using DDE Curtis A. Smith, Defense Contract Audit Agency, La Mirada, CA

SAS 9.4 Interface to Application Response Measurement (ARM)

SAS Comments How Straightforward Are They? Jacksen Lou, Merck & Co.,, Blue Bell, PA 19422

TIP: To access the WinRunner help system at any time, press the F1 key.

Computational Mathematics with Python

Microsoft Excel Tips & Tricks

Creating Basic Excel Formulas

Transcription:

ABSTRACT Getting the IN operator to FUNCTION inside a SAS Macro Perry Watts, Independent Consultant, Elkins Park, PA Large SAS macros with many parameters require that user values be checked at run time. One convenient checking tool is the IN operator that has been extended in 9.2 SAS to work inside a macro. Usage and syntax updates for the newly extended operator are included in the presentation. For those with earlier versions of SAS software, the INFCN ("in-function") macro has been developed to mimic the 9.2 IN operator. INFCN has been selected as a name, because the INDEXW function plays a major role in its operation. Also the macro has been implemented as a macro function so that it ends up working just like an operator. The crossover from function to operator is made possible by the fact that these structures can often be used interchangeably. In the paper, the interchangeability is demonstrated and the INFCN macro is reviewed in detail. PROBLEM DEFINITION In Building the Better Macro: Best Practices for the Design of Reliable, Effective Tools Frank DiIorio argues for consistency when using keyword parameters in a system of interrelated macros: Just as the presence of keyword parameters makes the macro more usable, so does consistency of how they are named and given values within a system of macros. Parameters that identify similar actions or content should be named consistently. Parameter values should also be coded consistent. [3, p.4] (italics added). From the quote, consistency among a set of macros not only applies to parameter names but also to their values. For example, DiIorio argues for a universal "yes" when assignments are made to boolean parameters: not a "yes" for one and a "t" for another. While there is no doubt that consistency improves the design and reliability of reusable software, few developers have the authority to restrict values supplied to macro parameters. While users have no choice but to adhere to default definitions, they typically want their macros to be "flexible". For example, in a graphics macro developed a few years ago, a percent bar chart had to be produced when any of the following were supplied to the CHARTTYPE parameter: PCT, CLASSPCT, GROUPPCT, SUBGROUPPCT, OAPCT, OTHERPCT, PERCENT, PERCENTAGE, PERCENTAGE, RPCT, MP100PCT, G100PCT, or SG100PCT If the IN operator worked in version 8 SAS Macro Language, this specification would have been easy to implement. However, here is the error message that is returned when version 9.2 SAS is not being used: ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: RPCT in PCT, CLASSPCT, GROUPPCT, SUBGROUPPCT, OAPCT, OTHERPCT, PERCENT, PERCENTAGE, PERCENTAGE, RPCT, MP100PCT, G100PCT, SG100PCT An application of %SYSFUNC doesn't work either. IN is an operator, not a function. Also, reliance upon %IF-%THEN- %ELSE statements is beyond the pale - especially in a macro that supports many such "flexible" parameters. Formats can provide a workaround, but they are unwieldy too. THE IN(#) OPERATOR WORKS IN A SAS 9.2 MACRO System options need to be defined to get the IN (or #) operator to work inside a SAS 9.2 macro. MINOPERATOR (for Macro-In-Operator) must be turned on, because the default is NOMINOPERATOR, and if the delimiter in the match list is not a space, it too must be specified with MINDELIMITER= [6,p.322-3]. The following, therefore, should work: options MINOPERATOR; %let excerpt=percent; %let matchlist=pct CLASSPCT GROUPPCT SUBGROUPPCT OAPCT PERCENT; %put %eval(&excerpt in &matchlist) /* Output = 1 */ options MINOPERATOR MINDELIMITER=','; %let excerpt=grouppct; %let matchlist=pct,classpct,grouppct,subgrouppct,oapct,percent; %put %eval(&excerpt # &matchlist) /* Output = 1 */ DIFFERENTIATING BETWEEN COMPARISON OPERATORS AND FUNCTIONS IN SAS Comparison operators in SAS include EQ, NE, GT, GE, LT, LE as well as IN [4,p.118-122]. Operators are used to evaluate the relationship between two operands, returning a '1' if the expression is TRUE, and a '0' if the expression is FALSE. 1

Functions differ in structure from operators. In SAS, a function operates on supplied arguments to perform a calculation or operation that is returned as a value [4,p.39]. Arguments always follow the function name and are enclosed in parentheses. A listing of SAS-supplied functions can be found in any version of the SAS Language Reference Dictionary manuals whereas user-defined functions are only available in the SAS macro language. For functions, the number of arguments can vary whereas comparison operators are nested between two operands. Despite their differences, operators and functions both provide return values. If the return value from a function is any non-zero number, SAS will treat it as TRUE when the function is used in an IF statement. Only zeroes are defined as FALSE. While the return values of '0' and '1' are more subtle for operators, they can, nevertheless, be inferred in the source code that follows: %macro TestIF; %let A=3; %let B=2; %if &A GT &B %then %do; %put Implicit: A is greater than B; %if &A GT &B EQ 1 %then %do; %put Explicit: A is greater than B; %if &B GT &A %then %do; %put Implicit: B NOT greater than A IS NOT PRINTED; %if &B GT &A EQ 0 %then %do; %put Explicit: B is NOT greater than A; %mend TestIf; %testif Output to the LOG from the macro: Implicit: A is greater than B Explicit: A is greater than B Explicit: B is NOT greater than A %if &A GT &B translates to %if 1, because the expression is TRUE. %if &A GT &B EQ 1 translates to %if 1 EQ 1 which is also TRUE. %if &B GT &A translates to %if 0, or FALSE meaning that the PUT statement is not executed. %if &B GT &A EQ 0 translates to %if 0 EQ 0, or TRUE meaning that the PUT statement is executed. Parentheses do not belong exclusively to the function. In Base SAS, the IN also operator uses them. This means that the IN operator and the INDEXW function have a similar appearance, and they can be used interchangeably to generate the same output from the data step below: data test; length A $10; A='xyzzy'; put 'By Operator'; if A in('deffde','xyzzy') then put 'IMPLICIT: A = deffde OR A = xyzzy'; if A in('deffde','xyzzy') NE 0 then put 'EXPLICIT: A = deffde OR A = xyzzy'; if A in('deffde','abcdef') eq 0 then put 'EXPLICIT: A ^= deffde and A ^= abcdef '; put 'BY Function'; if indexw('deffde xyzzy', A) then put 'IMPLICIT: A = deffde OR A = xyzzy'; if indexw('deffde xyzzy', A) NE 0 then put 'EXPLICIT: A = deffde OR A = xyzzy'; if indexw('deffde abcdef', A) eq 0 then put 'EXPLICIT: A ^= deffde and A ^= abcdef '; Output to the LOG from data set TEST is identical for both the IN operator and the INDEXW function: By Operator IMPLICIT: A = deffde OR A = xyzzy EXPLICIT: A = deffde OR A = xyzzy EXPLICIT: A ^= deffde and A ^= abcdef BY Function IMPLICIT: A = deffde OR A = xyzzy EXPLICIT: A = deffde OR A = xyzzy EXPLICIT: A ^= deffde and A ^= abcdef if indexw('deffde xyzzy', A) translates to if 8 or TRUE. In this example, a function call is being used as a conditional expression, since logical values in SAS are numeric. 2

Although functions and operators have a lot in common, assignment statements can only be used to store return values from functions, not operators. For example, the return value from executing indexw above was retrieved with: x = indexw('deffde xyzzy', A); /* x = 8 */ As a workaround, SAS nests operators within function calls to retrieve their output! In the data step below, a value of 1 is assigned to XX with an application of IFN that mimics the IF/THEN/ELSE construct [5,p.586]: data IfTrue; A = 3; B = 2; XX = ifn(a GT B, 1, 0); For the SAS macro language, the corresponding function is%eval: %let XX = %eval(&a GT &B); THE INFCN MACRO FUNCTION Given that return values from functions can be used in logical expressions makes it possible to solve the IN problem with INDEXW inside a macro. The INFCN macro is listed in full below: %macro InFcn (excerpt, matchlist); %local TorF quotes; %let quotes=%str(%'%"); %let excerpt = %nrbquote(%sysfunc(compress(&excerpt,"&quotes"))); %let matchlist = %sysfunc(translate(&matchlist,' ', ',')); %let matchlist = %nrbquote(%sysfunc(compress(&matchlist,"&quotes"))); %let TorF = %SYSFUNC(indexW(%upcase(&matchlist), %upcase(&excerpt))); &TorF ( %mend InFcn; InFcn is a macro function. Art Carpenter lists the following characteristics of macro functions in his SUGI 27 paper Macro Functions: How to Make Them - How to Use Them [2]: All statements in the macro must be macro statements beginning with a percent sign (%) or ampersand (&). The macro should create NO macro variables other than those that are local to that macro. (Macro parameters are local by definition). The macro should resolve to the value that is to be returned. The two positional parameters associated with INFCN are defined in IN-operator order; i.e. EXCERPT IN MATCHLIST translates to %INFcn(EXCERPT,MATCHLIST). For the INDEXW function, the order is reversed: indexw(matchlist,excerpt). Local macro variables are declared in the macro function. Single instances of single and double parentheses are masked with a % sign such that quotes = '". Working from the inside out: Quotes are not used to define character strings in the macro language. Therefore they are removed with the SAS COMPRESS function that is made available through SYSFUNC. NRBQUOTE (no-resolve blind quote) [1, p.155-159] masks character strings (NE) and macro symbols (%) In Base SAS, the delimiter for the match string in the IN operator is the comma whereas it is a space in the INDEXW function. Therefore, commas are replaced with spaces with an application of TRANSLATE. Again, working from inside out: Text is made case insensitive with the application of %UPCASE on both EXCERPT and MATCHLIST. The IndexW function returns a number between 0 and the position of the first character of the last word in the match-list. If the number equals zero, the expression will evaluate to FALSE, otherwise any positive integer will be treated as TRUE. The return value is assigned to the macro variable, TORF. Here is where TORF is actually returned - with an ampersand. Note the absence of a semicolon. The presence of one would cause problems in the calling program. INVOKING INFCN In the first example, the problem with the assignment to CHARTTYPE described in the opening paragraphs is solved: %macro getbarcharttype(thistype=, alltypes=); %local position chrttype; %let position = %infcn(&thistype,&alltypes); %put position = &position; %if %infcn(&thistype,&alltypes) %then %let chrttype=pct; %else %let chrttype=freq; &chrttype %mend getbarcharttype; 3

thistype=%, alltypes= % PCT CLASSPCT GROUPPCT SUBGROUPPCT OAPCT OTHERPCT PERCENT PERCENTAGE PERCENTAGE RPCT MP100PCT G100PCT SG100PCT ); thistype="classpct", alltypes= %nrstr('%','pct','classpct','grouppct','subgrouppct', 'oapct','otherpct','percent',' percentage', 'percentage','rpct','mp100pct','g100pct','sg100pct') ); thistype=count, alltypes= % PCT CLASSPCT GROUPPCT SUBGROUPPCT OAPCT OTHERPCT PERCENT PERCENTAGE PERCENTAGE RPCT MP100PCT G100PCT SG100PCT); %macro getbarcharttype The calling macro, GETBARCHARTTYPE, is also a macro function. In GETBARCHARTTYPE, INFCN is used first in an assignment statement and then in a conditional expression. In run #1, the % sign is successfully managed. With POSITION=1 (TRUE), PCT is assigned to CHARTTYPE. In run #2, mixed text parameters, commas, and quotation marks are also handled so that POSITION=7 (TRUE) and PCT is again assigned to CHARTTYPE. In run #3, COUNT cannot be found in the match string. Therefore, POSITION=0 (FALSE), and FREQ, the default value in this example, is assigned to CHARTTYPE. In the second example, the IN operator and the INFCN macro function are compared in two data steps that generate the same output. data one; /* WITH IN OPERATOR */ length ingroup $1; do i=1 to 10; if i in(1,4,5) then ingroup='y'; else ingroup='n'; output; end; title1 'Data: One'; proc print data=one; %macro enumerate; data OneAlso; length ingroup $1; %do i= 1 %to 10; i=&i; %if %infcn(&i,1 4 5) %then %str(ingroup='y';); %else %str(ingroup='n';); output; title1 'Data: OneAlso'; proc print data=onealso; %mend enumerate; %enumerate The conclusion for this brief paper is an exercise: Review the source code above and explain why data sets ONE and ONEALSO are the same. Use concepts drawn from the paper. REFERENCES [1] Carpenter, Art. Carpenter's Complete Guide to the SAS Macro Language: Second Edition. Cary, NC: SAS Institute Inc., 2004. [2] Carpenter, Arthur. Macro Functions: How to Make Them - How to Use Them. Proceedings of the Twenty- Seventh SAS User Group International Conference, Cary, NC: SAS Institute Inc., 2002, paper #100. [3] DiIorio, Frank. Building the Better Macro: Best Practices for the Design of Reliable, Effective Tools. Proceedings of the 21 st Annual Northeast SAS Users Group Conference. Pittsburgh, PA 2008, paper #FF11. SAS INSTITUTE REFERENCES: [4] SAS Institute Inc. SAS 9.1.3 Language Reference: Concepts. Cary NC: SAS Institute Inc., 2004. [5] SAS Institute Inc. SAS 9.1.3 Language Reference: Dictionary Volume 1. Cary NC: SAS Institute Inc., 2004. [6] SAS Institute Inc. SAS 9.2 Macro Language Reference. Cary NC: SAS Institute Inc., 2009. 4

SAS-L DISCUSSIONS ABOUT THE USE OF THE IN OPERATOR FOR MACROS: SAS-L@LISTSERV.UGA.EDU. Re: Help with Macro. Posted by Toby Dunn on 11 May 2007. Replaces the %INDEX macro function with the INDEXW SAS function for evaluating the match string in his macro, FINDIN. FINDIN uses %EVAL to return a value to the calling program - working, in effect, just like a macro function. SAS-L@LISTSERV.UGA.EDU. Re: Macro to convert Dates to 8601 format. Posted by Jim Groeneveld on 4 Nov 2008. He provides a link to his IN macro that also is a macro function. Groeneveld's IN macro uses a do-loop instead of INDEXW to check excerpt against match string. WHAT'S IN THE NESUG 2009 PROCEEDINGS OR AVAILABLE BY REQUEST: 1) The INFCN macro function (infcn.sas) 2) The calling program used for invoking INFCN (CallinFcn.sas) TRADEMARK CITATION SAS and all other SAS Institute Inc. product or service names are registered trademarks or trademarks of SAS Institute Inc. in the USA and other countries. indicates USA registration. Other brand and product names are registered trademarks or trademarks of their respective companies. CONTACT INFORMATION The author welcomes feedback via email at perrywatts@comcast.net. 5