Announcement

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

  • Replace negative number with its absolute in foreach macro local

    Dear Statalists,

    I'm trying to replace negative numbers with their absolutes in a foreach loop over macro local levels. However, what works outside the loop (-15 -> 15) no longer works within the loop (-15 -> --15).

    My example codes and results are as follows. Appreciate any advice!

    ****************************
    * Outside a loop:
    local item -15
    dis `item'
    if `item'<0{
    local newname -`item'
    }
    dis `newname'
    // result: -15

    ****************************
    * Within a loop:
    tempvar count_did2s
    gen `count_did2s' = 0

    // example local macro levels, actually generated from -levelsof-
    local test_levels -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5

    foreach item of local test_levels{
    dis `item'
    if `item' > 0{
    local newname "Effect`item'"
    dis "`newname'"
    }
    if `item' < 0{
    dis `item'
    local item2 -`item'
    local newname "Pre`item2'"
    dis "`newname'"
    // result: Pre--15
    }

    if `count_did2s' == 0{
    unab rename_list: "`newname'"
    replace `count_did2s' = `count_did2s' + 1
    }
    if `count_did2s' >= 1{
    local rename_list `rename_list' "`newname' "
    }

    }

    dis `rename_list'

    /*
    Error:
    "Pre--15 invalid name
    r(198); */


    Best,
    Yuting

  • #2
    At least a couple things here:

    Your code actually does not work outside the loop. When you do
    Code:
    local newname -`item'
    where `item' is -15, then actually newname is --15. You would see this if you did
    Code:
    dis "`newname'"
    But you do
    Code:
    dis `newname'
    Stata reads this as
    Code:
    dis --15
    then calculates what the negative of -15 would be, and displays 15.

    What you need to do instead is

    Code:
    local newname = -`item'
    so that Stata actually computes the negative of the number stored in the local item.

    So in your loop as well, you need


    Code:
    local item2 = -`item'

    That said, you can also simplify your code by using Stata's abs() function for calculating absolute values.

    Finally, when you use unab, you should remove the quotes, like so:

    Code:
    unab rename_list: `newname'
    Last edited by Hemanshu Kumar; 14 Aug 2022, 08:29.

    Comment


    • #3
      Thank you so much Hemanshu, this is extremely helpful!

      Sorry for my typo. Outside the loop, the `item' is 15. But you are totally right that "`item'" is also --15, so my code doesn't work there either.

      I had to keep those conditional part because I need different prefixes for positive and negative values in `newname'. But I guess the takeaway here is to use abs() for standard practice.

      And thank you for the final point. I added "" because `newname' wasn't a variable name. I'm trying to create a local macro list of string from a list of numbers. And you made me realize that unab is not the right command here because it takes variable(s).

      Comment


      • #4
        Glad it helped. If you give a concise description of the overall problem you're trying to solve here, people may be able to give suggestions for more efficient solutions.

        Comment


        • #5
          Originally posted by Hemanshu Kumar View Post
          Glad it helped. If you give a concise description of the overall problem you're trying to solve here, people may be able to give suggestions for more efficient solutions.
          Thanks! I'll keep this in mind next time I ask questions.

          In case people encounter similar issue in the future, this is an example of my final codes:


          local rename_list

          // example local macro levels, actually generated from -levelsof-
          local test_levels -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5

          foreach item of local test_levels{
          dis `item'

          if `item' > 0{
          local newname "Effect`item'"
          dis "`newname'"
          }
          if `item' < 0{
          dis `item'
          local item2 = abs(`item')
          local newname "Pre`item2'"
          dis "`newname'"
          }


          local rename_list `rename_list' `newname'
          dis "`rename_list'"
          }

          dis "`rename_list'"

          Comment

          Working...
          X