foreach using numlist of numbers with leading 0s - loops

In Stata, I am trying to use a foreach loop where I am looping over numbers from, say, 05-11. The problem is that I wish to keep the 0 as part of the value. I need to do this because the 0 appears in variable names. For example, I may have variables named Y2005, Y2006, Var05, Var06, etc. Here is an example of the code that I tried:
foreach year of numlist 05/09 {
...do stuff with Y20`year` or with Var`year`
}
This gives me an error that e.g. Y205 is not found. (I think that what is happening is that it is treating 05 as 5.)
Also note that I can't add a 0 in at the end of e.g. Y20 to get Y200 because of the 10 and 11 values.
Is there a work-around or an obvious thing I am not doing?

Another work-around is
forval y = 5/11 {
local Y : di %02.0f `y'
<code using local Y, which must be treated as a string>
}
The middle line could be based on
`: di %02.0f `y''
so that using another macro can be avoided, but at the cost of making the code more cryptic.
Here I've exploited the extra fact that foreach over such a simple numlist is replaceable with forvalues.
The main trick here is documented here. This trick avoids the very slight awkwardness of treating 5/9 differently from 10/11.
Note. To understand what is going on, it often helps to use display interactively on very simple examples. The detail here is that Stata is happily indifferent to leading zeros when presented with numbers. Usually this is immaterial to you, or indeed a feature as when you appreciate that Stata does not insist on a leading zero for numbers less than 1.
. di 05
5
. di 0.3
.3
. di .3
.3
Here we really need the leading zero, and the art is to see that the problem is one of string manipulation, the strings such as "08" just happening to contain numeric characters. Agreed that this is obvious only when understood.

There's probably a better solution but here's how this one goes:
clear
set more off
*----- example data -----
input ///
var2008 var2009 var2010 var2011 var2012
0 1 2 3 4
end
*----- what you want -----
numlist "10(1)12"
local nums 08 09 `r(numlist)'
foreach x of local nums {
display var20`x'
}
The 01...09 you can insert manually. The rest you build with numlist. Put all that in a local, and finally use it in the loop.
As you say, the problem with your code is that Stata will read 5 when given 05, if you've told it is a number (which you do using numlist in the loop).

Another solution would be to use an if command to count the number of characters in the looping value, and then if needed you can add a leading zero by reassigning the local.
clear
input var2008 var2009 var2010 var2011 var2012
0 1 2 3 4
end
foreach year of numlist 08/12{
if length("`year'") == 1 local year 0`year'
di var20`year'
}

Related

SPSS recoding variables data from multiple variables into boolean variables

I have 26 variables and each of them contain numbers ranging from 1 to 61. I want for each case of 1, each case of 2 etc. the number 1 in a new variable. If there is no 1, the variable should contain 2.
So 26 variables with data like:
1 15 28 39 46 1 12 etc.
And I want 61 variables with:
1 2 1 2 2 1 etc.
I have been reading about creating vectors, loops, do if's etc but I can't find the right way to code it. What I have done is just creating 61 variables and writing
do if V1=1 or V2=1 or (etc until V26).
recode newV1=1.
end if.
exe.
**repeat this for all 61 variables.
recode newV1 to newV61(missing=2).
So this is a lot of code and quite a detour from what I imagine it could be.
Anyone who can help me out with this one? Your help is much appreciated!
noumenal is correct, you could do it with two loops. Another way though is to access the VECTOR using the original value though, writing that as 1, and setting all other values to zero.
To illustrate, first I make some fake data (with 4 original variables instead of 26) named X1 to X4.
*Fake Data.
SET SEED 10.
INPUT PROGRAM.
LOOP Id = 1 TO 20.
END CASE.
END LOOP.
END FILE.
END INPUT PROGRAM.
VECTOR X(4,F2.0).
LOOP #i = 1 TO 4.
COMPUTE X(#i) = TRUNC(RV.UNIFORM(1,62)).
END LOOP.
EXECUTE.
Now what this code does is create four vector sets to go along with each variable, then uses DO REPEAT to actually refer to the VECTOR stub. Then finishes up with RECODE - if it is missing it should be coded a 2.
VECTOR V1_ V2_ V3_ V4_ (61,F1.0).
DO REPEAT orig = X1 TO X4 /V = V1_ V2_ V3_ V4_.
COMPUTE V(orig) = 1.
END REPEAT.
RECODE V1_1 TO V4_61 (SYSMIS = 2).
It is a little painful, as for the original VECTOR command you need to write out all of the stubs, but then you can copy-paste that into the DO REPEAT subcommand (or make a macro to do it for you).
For a more simple illustration, if we have our original variable, say A, that can take on integer values from 1 to 61, and we want to expand to our 61 dummy variables, we would then make a vector and then access the location in that vector.
VECTOR DummyVec(61,F1.0).
COMPUTE DummyVec(A) = 1.
For a record if A = 10, then here DummyVec10 will equal 1, and all the others DummyVec variables will still by system missing by default. No need to use DO IF for 61 values.
The rest of the code is just extra to do it in one swoop for multiple original variables.
This should do it:
do repeat NewV=NewV1 to NewV61/vl=1 to 61.
compute NewV=any(vl,v1 to v26).
end repeat.
EXPLANATION:
This syntax will go through values 1 to 61, for each one checking whether any of the variables v1 to v26 has that value. If any of them do, the right NewV will receive the value of 1. If none of them do, the right NewV will receive the value of 0.
Just make sure v1 to v26 are consecutively ordered in the file. if not, then change to:
compute NewV=any(vl,v1, v2, v3, v4 ..... v26).
You need a nested loop: two loops - one outer and one inner.

Stata Nested foreach loop substring comparison

I have just started learning Stata and I'm having a hard time.
My problem is this: I have two different variables, ATC and A, where A is potentially a substring of ATC.
Now I want to mark all the observations in which A is a substring of ATC with OK = 1.
I tried this using a simple nested loop:
foreach x in ATC {
foreach j in A {
replace OK = 1 if strpos(`x',`j')!=0
}
}
However, whenever I run this loop no changes are being made even though there should be plenty.
I feel like I should probably give an index specifying which OK is being changed (the one belonging to the ATC/x), but I have no idea how to do this. This is probably really simple but I've been struggling with it for some time.
I should have clarified: my A list is separate from the main list (simply appended to it) and only contains unique keys which I use to identify the ATCs which I want. So I have ~120 A-keys and a couple million ATC keys. What I wanted to do was iterate over every ATC key for every single A-key and mark those ATC-keys with A that qualify.
That means I don't have complete tuples of (ATC,A,OK) but instead separate lists of different sizes.
For example: I have
ATC OK A
ABCD 0 .
EFGH 0 .
... ... ...
. . AB
. . ET
and want the result that "ABCD" having OK is marked as 1 while "EFGH" remains at 0.
We can separate your question into two parts. Your title implies a problem with loops, but your loops are just equivalent to
replace OK = 1 if strpos(ATC, A)!=0
so the use of looping appears irrelevant. That leaves the substring comparison.
Let's supply an example:
. set obs 3
obs was 0, now 3
. gen OK = 0
. gen A = cond(_n == 1, "42", "something else")
. gen ATC = "answer is 42"
. replace OK = 1 if strpos(ATC, A) != 0
(1 real change made)
. list
+------------------------------------+
| OK A ATC |
|------------------------------------|
1. | 1 42 answer is 42 |
2. | 0 something else answer is 42 |
3. | 0 something else answer is 42 |
+------------------------------------+
So it works fine; and you really need to give a reproducible example if you think you have something different.
As for specifying where the variable should be changed: your code does precisely that, as again the example above shows.
The update makes the problem clear. Stata will only look in the same observation for a matching substring when you specify the syntax you gave. A variable in Stata is a field in a dataset. To cycle over a set of values, something like this should suffice
gen byte OK = 0
levelsof A, local(Avals)
quietly foreach A of local Avals {
replace OK = 1 if strpos(ATC, `"`A'"') > 0
}
Notes:
Specifying byte cuts down storage.
You may need an if or in restriction on levelsof.
quietly cuts out messages about changed values. When debugging, it is often better left out.
> 0 could be omitted as a positive result from strpos() is automatically treated as true in logical comparisons. See this FAQ.

Printing out a set of lists in the ti-84 ti-basic

I want to be able to print out L1 up to Lk (lists in the ti-84) for some arbitrary number k.
Lists in ti-basic are essentially one-dimensional arrays used to store a real or complex number into each of their elements.
Below I made my own lists named L1, ... L3 (not built in, in reality can be accessed and printed by typing LL1, ... LL3)
I will show you some of what I tried, etc.
let L5 = {5,5,5}
If I try the following code snippet:
PROGRAM: ITRTLST
:ClrHome
:Disp LL1
:For(J,1,3
:Disp J
:Disp LL5
:End
This code outputs:
1
{5,5,5}
2
{5,5,5}
3
{5,5,5}
Note the first 'L' in LL5 is a token (accessible by pressing [2nd]+[LIST(STAT)] OPS B:)
However if I try the following code snippet:
PROGRAM: ITRTLST
:ClrHome
:Disp LL1
:For(k,1,3
:Disp J
:Disp LLk
:End
I get ERR:UNDEFINED
This is because it thinks of 'LLK' as a list name rather than LL1, LL2, LL3
We can see this if I let LLK = {1,2,3} then the above code outputs
1
{1,2,3}
2
{1,2,3}
3
{1,2,3}
This can be done but it is a pain, and will probably be very slow.
Try this code, with [Max] replaced with a number:
:ClrHome
:For(I,1,[Max])
:"Convert I into a string, this is slow
:I/10→D
:sub("0123456789",10*fPart(D)+1,1)→Str1
:int(D)→D
:While D>0
:D/10→D
:sub("0123456789",10*fPart(D)+1,1)+Str1→Str1
:int(D)→D
:End
:"Display the I'th list
:Disp expr("ʟL" + Str1)
:End
Note that the lines starting with " are just comments and can be removed.
This is a pretty ugly (and possibly the only) method, but it is possible to do this by running a bunch of If commands.
For example,
Disp ʟL1
If K≥2
Disp ʟL2
If K≥3
Disp ʟL3
If K≥4
Disp ʟL4
If K≥5
Disp ʟL5
So on and so forth.
EDIT: I don't know if you still need an answer to this question, but I found a way to do exactly what you want. It's still very messy, though.
Convert your number to a string, like Str0 (You can choose from a couple ways: link1 link2).
Concatenate that number with the list name. For example, "ʟL" + Str0 → Str0.
Evaluate the string with expr(.
As I said, this is very much ugly, and all those number-to-string conversions can't be too efficient, so you're probably better off copy-pasting a bunch of If statements for each condition.
Alternatively, you can compress all the lists you're using into a single big list, and have the start positions of each list stored in another list. Then you can extract any sublist you want from the big compress list with the seq( command.
There's no way to do that in TI-Basic. Just as there's no way to go from a string "X" to the contents of the variable X, there's no way to go from a number ot a list with that number in its name.
UPDATE: It turns out you can use expr("X") to get the value of X. And you can do that same with lists.
But alternatively, if you want to store a 2-dimensional array of data, TI-Basic does have matrices, although they are somewhat restricted compared to lists (in particular, you cannot create named matrices). If you need some data structure more complex than that, you may have reached the limits of this language.

Filling an array, A$(X,X) in Commodore BASIC?

I am trying to fill A$(X,X) with "."s in Commodore BASIC.
This is what I have so far....but I'm not really sure what to do concerning ASCII values and such. Any commentary?
INPUT A$
FOR I = 0 TO X = DIM A$(X,X)
A$(".",x)
I'm still EXTREMELY confused on PET BASIC's API... Any suggestions would be GREATLY appreciated.
My answers are based around a youth in front of a Commodore 64 and may not be completely correct for the PET series. But seeing as you haven't had any other answers yet I'll give it a bash.
In the first line of your code you are requesting a string from the user and storing it in A$. The dollar sign denotes the variable is a string. In the second line, you are redefining A$ as a two dimensional array. The dimensions are both X which hasn't been defined. I don't recall DIM having a return value but I could be wrong.
The function to get an ASCII value from a char is ASC() and to convert back you use CHR$() such:
10 NUMA = ASC("A"): REM NUMA now contains 65
20 CHARA$ = CHR$(NUMA): REM CHARA$ now contains "A"
Something you should know is that these functions use "PET ASCII" which is slightly different to ASCII. It never caused me any problems but its something to remember.
FOR loops always have a NEXT to end the block such:
10 FOR A = 1 TO 10
20 PRINT A: REM Displays series of numbers.
30 NEXT
I'm not entirely clear what you're trying to achieve but hopefully I have at least given you enough pieces to work it out. From what I understand, you need something like:
10 INPUT "Please enter a number:", X
20 DIM A$(X, X)
30 FOR I = 0 TO X
40 FOR J = 0 TO X
50 A$(I, J) = "."
60 NEXT
70 NEXT

Display data in Stata loop

I have a loop in Stata 12 that looks at each record in a file and if it finds a flag equal to 1 it generates five imputed values. My code looks like this:
forvalues i=1/5 {
gen y3`i' = y2
gen double h`i' = (uniform()*(1-a)+a) if flag==1
replace y3`i' = 1.6*(invibeta(7.2,2.6,h`i')/(1-invibeta(7.2,2.6,h`i')))^(1/1.7) if
flag==1
}
a is defined elsewhere. I want to check the individual imputations. Thus, I need to display the imputed variable preferably only for those cases where flag=1. I also would like to display another value, s, alongside. I need help in figuring out the syntax. I've tried every combination of quotes and subscripts that I can think of, but I keep getting error messages.
One other useful modification occurs to me. Suppose I have three concatenated files on which I want to perform this routine. Let them have a variable file equal to 1, 2 or 3. I'd like to set a separate seed for each and do it in my program so I have a record. I envision something like:
forvalues j=1/3 {
set seed=12345 if file=1
set seed=56789 if file=2
set seed=98765 if file=3
insert code above
}
Will this work?
No comment is possible on code you don't show, but the word "display" may be misleading you.
list y3`i' if flag == 1
or some variation may be what you seek. Note that display is geared to showing at most one line of output at a time.
P.S. As you are William Shakespeare, know that the mug http://www.stata.com/giftshop/much-ado-mug/ was inspired by your work.
A subsidiary question asks about choosing a different seed each time around a loop. That is easy:
forval j = 1/3 {
local seed : word `j' of 12345 56789 98765
set seed `seed'
...
}
or
tokenize 12345 56789 98765
forval j = 1/3 {
set seed ``j''
...
}

Resources