Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Referencing a multi-word sub-macro of a list via `word `i' ...'

    I am trying to dynamically create titles for a graph by referencing sub-strings from a macro list. Some of these strings contain multiple words. Intuitively, I tried the following:

    Code:
    local industries_string "Mining, Water & Energy" "Manufacturing" "Health & Education" "Construction" "Retail" "Transportation & Communication" "Hospitality & Food" "Arts & Other Services" "Finance" "Professional Services" "Administration" "Public Services"
    
    forvalues i=1/12{
    local industry_string `: word `i' of `industries_string''
    di "`industry_string'"
    }
    However, Stata seems to interpret the first (and only the first) macro of the list "Mining, Water, & Energy" as separate words, giving me the following output:

    Code:
    . local industries_string "Mining, Water & Energy" "Manufacturing" "Health & Education" "Construction" "Retail" "Transportation &
    >  Communication" "Hospitality & Food" "Arts & Other Services" "Finance" "Professional Services" "Administration" "Public Service
    > s"
    .
    . forvalues i=1/12{
      2.         local industry_string `: word `i' of `industries_string''
      3.         di "`industry_string'"
      4. }
    Mining,
    Water
    &
    Energy
    Manufacturing
    Health & Education
    Construction
    Retail
    Transportation & Communication
    Hospitality & Food
    Arts & Other Services
    Finance
    There must be a simple reason why this works with later sub-macros such as "Health & Education", but not with the first one. Perhaps the `: word ...' syntax isn't the best way to achieve this in the first place?

  • #2
    The principle is that the outermost quotation marks are stripped when evaluating local macro references. So

    Code:
    local foo "a" "b" "c"
    gets interpreted as

    Code:
    a" "b" "c
    So, you need to protect your string by adding a sacrificial outer pair of quotation marks. In this context I advise that you use the special characters `" "' for clarity.


    Here is some technique.


    Code:
    local industries_string `" "Mining, Water & Energy" "Manufacturing" "Health & Education" "Construction" "Retail" "Transportation & Communication" "Hospitality & Food" "Arts & Other Services" "Finance" "Professional Services" "Administration" "Public Services" "'
    
    forvalues i=1/12 {
    local industry_string : word `i' of `industries_string'
    di "`industry_string'"
    }
    
    tokenize `" "Mining, Water & Energy" "Manufacturing" "Health & Education" "Construction" "Retail" "Transportation & Communication" "Hospitality & Food" "Arts & Other Services" "Finance" "Professional Services" "Administration" "Public Services" "'
    
    mac li

    Comment


    • #3
      Originally posted by Nick Cox View Post
      The principle is that the outermost quotation marks are stripped when evaluating local macro references. So

      Code:
      local foo "a" "b" "c"
      gets interpreted as

      Code:
      a" "b" "c
      So, you need to protect your string by adding a sacrificial outer pair of quotation marks. In this context I advise that you use the special characters `" "' for clarity.


      Here is some technique.


      Code:
      local industries_string `" "Mining, Water & Energy" "Manufacturing" "Health & Education" "Construction" "Retail" "Transportation & Communication" "Hospitality & Food" "Arts & Other Services" "Finance" "Professional Services" "Administration" "Public Services" "'
      
      forvalues i=1/12 {
      local industry_string : word `i' of `industries_string'
      di "`industry_string'"
      }
      
      tokenize `" "Mining, Water & Energy" "Manufacturing" "Health & Education" "Construction" "Retail" "Transportation & Communication" "Hospitality & Food" "Arts & Other Services" "Finance" "Professional Services" "Administration" "Public Services" "'
      
      mac li
      Thank you, this is a very helpful insight and solves my problem!

      Comment


      • #4
        I don't know whether you'd find it any more convenient, but with the advent of frames, you have more options to store arrays of strings than in a local macro, which as you've seen can get a little tricky.

        You can store them in a string variable in a auxiliary frame and retrieve them by observation number (row number).

        Slightly more involved, but you can also park them in a Mata string vector and retrieve them by index on the fly.
        Code:
        version 18.0
        
        clear *
        
        *
        * frame approach
        *
        frame create Industries
        
        frame Industries {
            #delimit ;
            input str50 title; "Mining, Water & Energy"; "Manufacturing";
                "Health & Education"; "Construction"; "Retail";
                "Transportation & Communication"; "Hospitality & Food";
                "Arts & Other Services"; "Finance"; "Professional Services";
                "Administration"; "Public Services";
            end;
            #delimit cr
        }
        
        // Retrieval is fairly easy
        forvalues i = 1/12 {
            frame Industries: local industry_string = title[`i']
            display in smcl as result "`industry_string'"
        }
        
        *
        * Mata string vector approach
        *
        mata:
        Titles = "Mining, Water & Energy", "Manufacturing",
                "Health & Education", "Construction", "Retail",
                "Transportation & Communication", "Hospitality & Food",
                "Arts & Other Services", "Finance", "Professional Services",
                "Administration", "Public Services"
        end
        
        // Creation (above) is straightforward; retrieval isn't _too_ bad
        forvalues i = 1/12 {
            mata: st_local("industry_string", Titles[strtoreal(st_local("i"))])
            display in smcl as result "`industry_string'"
        }
        
        exit

        Comment


        • #5
          Originally posted by Joseph Coveney View Post
          I don't know whether you'd find it any more convenient, but with the advent of frames, you have more options to store arrays of strings than in a local macro, which as you've seen can get a little tricky.

          You can store them in a string variable in a auxiliary frame and retrieve them by observation number (row number).

          Slightly more involved, but you can also park them in a Mata string vector and retrieve them by index on the fly.
          Code:
          version 18.0
          
          clear *
          
          *
          * frame approach
          *
          frame create Industries
          
          frame Industries {
          #delimit ;
          input str50 title; "Mining, Water & Energy"; "Manufacturing";
          "Health & Education"; "Construction"; "Retail";
          "Transportation & Communication"; "Hospitality & Food";
          "Arts & Other Services"; "Finance"; "Professional Services";
          "Administration"; "Public Services";
          end;
          #delimit cr
          }
          
          // Retrieval is fairly easy
          forvalues i = 1/12 {
          frame Industries: local industry_string = title[`i']
          display in smcl as result "`industry_string'"
          }
          
          *
          * Mata string vector approach
          *
          mata:
          Titles = "Mining, Water & Energy", "Manufacturing",
          "Health & Education", "Construction", "Retail",
          "Transportation & Communication", "Hospitality & Food",
          "Arts & Other Services", "Finance", "Professional Services",
          "Administration", "Public Services"
          end
          
          // Creation (above) is straightforward; retrieval isn't _too_ bad
          forvalues i = 1/12 {
          mata: st_local("industry_string", Titles[strtoreal(st_local("i"))])
          display in smcl as result "`industry_string'"
          }
          
          exit
          Also very helpful - I wasn't aware of frames until now, I will look into this! For my simple case this may be too involved, but I can see how I might use this for more complex programs.

          Comment

          Working...
          X