Announcement

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

  • inverse order of global macro list

    HI,

    I would like to inverse the order of a global macro list:

    Code:
    global M_per 6 12 24 36 72 120
    
    * This is the output I would like to get:
    global M_per_minus 120 72 36 24 12 6
    Can someone help? Thanks


  • #2
    You undoubtedly could do it another way, but here's one approach.

    .ÿ
    .ÿversionÿ16.1

    .ÿ
    .ÿclearÿ*

    .ÿ
    .ÿlocalÿline_sizeÿ`c(linesize)'

    .ÿsetÿlinesizeÿ79

    .ÿ
    .ÿmata:
    -------------------------------------------------ÿmataÿ(typeÿendÿtoÿexit)ÿ-----
    :ÿmataÿsetÿmatastrictÿon

    :ÿ
    :ÿvoidÿfunctionÿrevglo(stringÿscalarÿmacro_name)ÿ{
    >ÿÿÿÿtransmorphicÿmatrixÿMÿ
    >ÿÿÿÿÿÿÿÿÿMÿ=ÿstrtoreal(tokens(st_global(macro_name))')
    >ÿÿÿÿÿÿÿÿÿMÿ=ÿsort((range(1,ÿrows(M),ÿ1),ÿM),ÿ-1)
    >ÿÿÿÿÿÿÿÿÿMÿ=ÿM[.,ÿ2]
    >ÿÿÿÿÿÿÿÿÿst_global(macro_name,ÿinvtokens(strofreal(M')))
    >ÿ}

    :ÿend
    -------------------------------------------------------------------------------

    .ÿ
    .ÿglobalÿM_perÿ6ÿ12ÿ24ÿ36ÿ72ÿ120

    .ÿmata:ÿrevglo("M_per")

    .ÿ
    .ÿdisplayÿinÿsmclÿasÿtextÿ"$M_per"
    120ÿ72ÿ36ÿ24ÿ12ÿ6

    .ÿ
    .ÿsetÿlinesizeÿ`line_size'

    .ÿ
    .ÿexit

    endÿofÿdo-file


    .


    You might just want to pause, step back and see if all the hoops that you're jumping through are really necessary to accomplish what it is that you're ultimately trying to.

    Comment


    • #3
      I do not use globals much, and do not remember by heart the rules of dereferencing them. So you need to adjust the code below to replace my locals with your globals.

      But for locals this is how this can be done:

      Code:
      . local M_per 6 12 24 36 72 120
      
      . foreach el in `M_per' {
        2. local M_per_minus `el' `M_per_minus'
        3. }
      
      . dis "`M_per_minus'"
      120 72 36 24 12 6

      Comment


      • #4
        Joro: It seems like this methods is not robust to comments /* ...*/ included in the variable M_per:
        Code:
        * Number of periods 
        global M_per 6 12 24 36 72 120 /*240*/
        foreach el in $M_per {
            global M_per_minus `el' $M_per_minus
        }
        dis "$M_per_minus"
        Any idea to fix this?

        Joseph: Elegant method in Mata. I am trying to be lean in terms of numbers of lines of code (which is not necessarily computationally efficient, agreed, but easier to read). Is there a robust 1-2 line method?


        Comment


        • #5
          Originally posted by Francois Durant View Post
          Joro: It seems like this methods is not robust to comments /* ...*/ included in the variable M_per
          True if Joro's code is run interactively at the command line, but it is robust to this if it's run as a do-file.

          I am trying to be lean in terms of numbers of lines of code (which is not necessarily computationally efficient, agreed, but easier to read). Is there a robust 1-2 line method?
          I guess the point is that if you're going to run this many times, then creating a Mata function, or putting Joro's code into a Stata program (see below), will result in a one-line method after the function or program is created. My function takes the name of any arbitrary global macro and substitutes the reversed sequence back into that same global macro, which is what you asked for. Adding another line to Joro's approach is required to do the same, but it's not a problem.

          .ÿ
          .ÿversionÿ16.1

          .ÿ
          .ÿclearÿ*

          .ÿ
          .ÿprogramÿdefineÿrevglo
          ÿÿ1.ÿÿÿÿÿÿÿÿÿversionÿ16.1
          ÿÿ2.ÿÿÿÿÿÿÿÿÿsyntaxÿanything(name=macro_name)
          ÿÿ3.ÿ
          .ÿÿÿÿÿÿÿÿÿforeachÿelÿofÿglobalÿ`macro_name'ÿ{
          ÿÿ4.ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿlocalÿM_per_minusÿ`el'ÿ`M_per_minus'
          ÿÿ5.ÿÿÿÿÿÿÿÿÿ}
          ÿÿ6.ÿÿÿÿÿÿÿÿÿglobalÿ`macro_name'
          ÿÿ7.ÿÿÿÿÿÿÿÿÿglobalÿ`macro_name'ÿ`M_per_minus'
          ÿÿ8.ÿend

          .ÿ
          .ÿ
          .ÿ
          .ÿglobalÿM_perÿ6ÿ12ÿ24ÿ36ÿ72ÿ120ÿ/*240*/

          .ÿ
          .ÿrevgloÿM_per

          .ÿ
          .ÿdisplayÿinÿsmclÿasÿtextÿ"$M_per"
          120ÿ72ÿ36ÿ24ÿ12ÿ6

          .ÿ
          .ÿexit

          endÿofÿdo-file


          .ÿ


          My point is that you seem to be doing a lot of unusual stuff with global macros, which seem to me would be easier with you started from scratch in Mata taking advantage of its string rowvectors and so on.

          Comment


          • #6
            . . . would be easier if you started from scratch in Mata . . .

            Comment


            • #7
              HI Francois Durant I happened to need something similar and found this post.

              This is probably an overkill, but just in case you need to reverse the order of macros constantly, this might work for you (based on Joseph Coveney 's code above),


              Code:
              cap mata: mata drop plocal() pglobal() reverse_macro()
              mata:
              
              //========================================================
              // Reverse macro order
              //========================================================
              //------------CReate own functions for built-in 
              function plocal(x, | y)  {
                  if (args() == 1) return(st_local(x))
                  else             return(st_local(x,y))
              } 
              function pglobal(x, | y)  {
                  if (args() == 1) return(st_global(x))
                  else             return(st_global(x,y))
              }
              
              //------------actual reverse
              void reverse_macro(string scalar name, | /* 
              */                     real scalar islocal)
              {
                  // define objects
                  string colvector M
                  real   colvector o
                  pointer(real scalar function) scalar fn
                  real scalar rv
                  
                  // setup
                  if (args() == 1) islocal = 1
                  else {
                      rv = anyof((0\1), islocal) // right values
                      if (rv == 0) {
                          _error("islocal must be either 0 or 1")
                      }
                  }
                  if (islocal == 1) fn = &plocal()
                  else              fn = &pglobal()
                  
                  // actual reverse
                  
                  M = tokens((*fn)(name))'
                  o = range(rows(M), 1, 1)
                  M = M[o]
                  
                  // return
                  (*fn)(name, invtokens(M'))    
              }
              
              end
              
              
              // Stata program that reads Mata function above. 
              discard
              cap program drop reverse_macro
              program define reverse_macro
                  syntax anything(name=name), [ISGlobal]
                  if ("`isglobal'" == "") mata: reverse_macro("`name'")
                  else                    mata: reverse_macro("`name'", 0)
              end
              
              
              // local and global to reverse
              global a 1 2 3 4
              local  a 7 8 9 0
              
              // Using mata directly
              mata: reverse_macro("a") // reverse local
              disp "`a'"
              . 0 9 8 7
              
              // using Stata
              reverse_macro a, isglobal // reverse global
              disp "$a"
              . 4 3 2 1
              Hope it helps
              Last edited by RAndres Castaneda; 23 May 2023, 10:57. Reason: unintentionally, I posted before finishing

              Comment

              Working...
              X