DATA Step, Macro, Functions and more

Dynamic apply format by making the fmtname from a value in the same dataset

Accepted Solution Solved
Reply
Contributor
Posts: 51
Accepted Solution

Dynamic apply format by making the fmtname from a value in the same dataset

[ Edited ]

Hello

 

I am using SAS9.4 on  a Windows10 PC environment.

 

I am trying to create a string column to contain a full description by using a format within a PUT statement.  I want the format name to be generated dynamically based on a value in a different column.   This seems feasible but I can't quite nail it, example program attached.

 

I have this problem on a couple of programs so all help will be gratefully received, thank you.

Attachment

Accepted Solutions
Solution
‎02-24-2017 05:43 AM
Valued Guide
Posts: 505

Re: Dynamic apply format by making the fmtname from a value in the same dataset

/* T1002580 Using putc or putn with format names in your data

Using putc or putn with format names in your data

This seems to work

inspired by
https://goo.gl/ktxY1O
https://communities.sas.com/t5/Base-SAS-Programming/Dynamic-apply-format-by-making-the-fmtname-from-a-value-in-the/m-p/335244

HAVE
====

proc format;
      value $ FMTA1X
      "A" = "this was discount $10"
      "B" = "this was discount $20"
      ;

      value $ FMTA2X
      "A" = "this was discount $300"
      "B" = "this was discount $400"
            ;
run;

Up to 40 obs WORK.HAVE total obs=5

Obs    PRODTYPE    DISCOUNT

 1        A1          B
 2        A2          A
 3        A2          A
 4        A2          B
 5        A1          B

WANT
====

Up to 40 obs WORK.DEMO_DESCRIPTION_HARDCODE total obs=5

Obs    PRODTYPE    DISCOUNT        DISCOUNT_DESC

 1        A1          B        this was discount $20   putc(discount,$fmta1x.)
 2        A2          A        this was discount $300
 3        A2          A        this was discount $300
 4        A2          B        this was discount $400
 5        A1          B        this was discount $20


SOLUTION
========

data have;
input Prodtype $ Discount $;
cards4;
A1 B
A2 A
A2 A
A2 B
A1 B
;;;;
run;quit;

data want;
  retain prodtype discount discount_desc;
  length discount_desc $44;
  set have;

  fmt=cats('$fmt',prodtype,'x');
  Discount_desc = putc(Discount,fmt);

run;quit;


Up to 40 obs WORK.WANT total obs=5

Obs    PRODTYPE    DISCOUNT        DISCOUNT_DESC           FMT

 1        A1          B        this was discount $20     $fmtA1x
 2        A2          A        this was discount $300    $fmtA2x
 3        A2          A        this was discount $300    $fmtA2x
 4        A2          B        this was discount $400    $fmtA2x
 5        A1          B        this was discount $20     $fmtA1x

View solution in original post


All Replies
Super User
Posts: 7,778

Re: Dynamic apply format by making the fmtname from a value in the same dataset

Posted in reply to RB1Kenobi

Not possible.

The format is set when the data step is compiled, so formats need to be named literally.

From the documentation of the put() function:

format.

contains the SAS format that you want applied to the value that is specified in the source. This argument must be the name of a format with a period and optional width and decimal specifications, not a character constant, variable, or expression.

(Emphasis by me)

 

Read the documentation.

 

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Super User
Super User
Posts: 7,945

Re: Dynamic apply format by making the fmtname from a value in the same dataset

Posted in reply to RB1Kenobi

Post your examples as text in a code window ({i} above post).  Is there a reason you want to try to automate it, you will need to have the list somewhere if so.  If its just a couple then what you have is fine.  To automate will take more code:

data fmts;
  length fmt_cond fmt $200;
  input fmt_cond $ fmt $;
datalines;
A1 $fmt2
A2 $fmt1
;
run;

data _null_;
  set fmts  end=last;
  if _n_=1 then call execute('data want;  set have;');
  call execute('if variable="'||strip(fmt_cond)||'" then res=put(   ...);
  if last then call execute('run;');
run;

Just as an example, however I would really question why this is necessary at all.

Super User
Posts: 19,789

Re: Dynamic apply format by making the fmtname from a value in the same dataset

[ Edited ]
Posted in reply to RB1Kenobi

PUTC/PUTN allow format names that are from a variable. 

 

Borrowing code:

 

data fmts;
length fmt_cond fmt $200;
input fmt_cond $ fmt $;
datalines;
A1 $fmt2
A2 $fmt1
;
run;

 

Data want;

set fmts;

 

want_var = putc(fmt_cond, fmt);

Run;

Trusted Advisor
Posts: 1,019

Re: Dynamic apply format by making the fmtname from a value in the same dataset

Posted in reply to RB1Kenobi

I suspect you would also be well served by a hash lookup table, keyed on 2 vars: PRODTYPE and DISCOUNT.  Make a lookup dataset, with all the expected combinations of prodtype,discount, and discount_desc.  Then load it into a hash object to use in the data step:

 

data lookup;
  input  prodtype :$2. discount :$1. @6 discount_desc $30.;
datalines;
A1 A this was discount $10
A1 B this was discount $20
A2 A this was discount $300
A2 B this was discount $400
run;

data demo_description_dynamic (drop=rc);
  set demodata;
  if _n_=1 then do;
    if 0 then set lookup;
    declare hash h (dataset:'lookup');
      h.definekey('prodtype','discount');
      h.definedata(all:'Y');
      h.definedone();
  end;
  rc=h.find();
  if rc^=0 then call missing(discount_desc);
run;

 

When the h.find() method is successful, two things happen:  RC=0 and discount_desc is retrieved from the desired item in hash object h.  If it's unsuccessful, RC ^=0 and discount_desc is unchanged from the last successful h.find().  That's why you see discount_desc set to missing when rc^=0.

Solution
‎02-24-2017 05:43 AM
Valued Guide
Posts: 505

Re: Dynamic apply format by making the fmtname from a value in the same dataset

/* T1002580 Using putc or putn with format names in your data

Using putc or putn with format names in your data

This seems to work

inspired by
https://goo.gl/ktxY1O
https://communities.sas.com/t5/Base-SAS-Programming/Dynamic-apply-format-by-making-the-fmtname-from-a-value-in-the/m-p/335244

HAVE
====

proc format;
      value $ FMTA1X
      "A" = "this was discount $10"
      "B" = "this was discount $20"
      ;

      value $ FMTA2X
      "A" = "this was discount $300"
      "B" = "this was discount $400"
            ;
run;

Up to 40 obs WORK.HAVE total obs=5

Obs    PRODTYPE    DISCOUNT

 1        A1          B
 2        A2          A
 3        A2          A
 4        A2          B
 5        A1          B

WANT
====

Up to 40 obs WORK.DEMO_DESCRIPTION_HARDCODE total obs=5

Obs    PRODTYPE    DISCOUNT        DISCOUNT_DESC

 1        A1          B        this was discount $20   putc(discount,$fmta1x.)
 2        A2          A        this was discount $300
 3        A2          A        this was discount $300
 4        A2          B        this was discount $400
 5        A1          B        this was discount $20


SOLUTION
========

data have;
input Prodtype $ Discount $;
cards4;
A1 B
A2 A
A2 A
A2 B
A1 B
;;;;
run;quit;

data want;
  retain prodtype discount discount_desc;
  length discount_desc $44;
  set have;

  fmt=cats('$fmt',prodtype,'x');
  Discount_desc = putc(Discount,fmt);

run;quit;


Up to 40 obs WORK.WANT total obs=5

Obs    PRODTYPE    DISCOUNT        DISCOUNT_DESC           FMT

 1        A1          B        this was discount $20     $fmtA1x
 2        A2          A        this was discount $300    $fmtA2x
 3        A2          A        this was discount $300    $fmtA2x
 4        A2          B        this was discount $400    $fmtA2x
 5        A1          B        this was discount $20     $fmtA1x
Contributor
Posts: 51

Re: Dynamic apply format by making the fmtname from a value in the same dataset

Posted in reply to RB1Kenobi

Thank you all for your contributions. 

The other way I was looking at the problem was to use create a function (Proc FCMP) which would have been stored in one place and then reference across the different programs.

☑ This topic is solved.

Need further help from the community? Please ask a new question.

Discussion stats
  • 6 replies
  • 213 views
  • 2 likes
  • 6 in conversation