How can I access arguments by their index in SPSS macros? - spss

I have defined a macro as:
DEFINE !testMacro (actDS = !TOKENS(1)
/var = !TOKENS(1)
/factors = !ENCLOSE('(',')'))
And I call it this way:
!testMacro actDS=testDataSet var=var1 factors=(A B C).
My question is how can I access the factors by index in the macro? For example, I want to split the dataset by the second factor (B).

The usual use of getting a list like factors into the macro is to loop on it and perform the same actions on each (see first example in below syntax).
If you want to use a single item in the list separately, the easiest way would be to just call it into the macro separately. If you have to call it in the list and still have to use it separately you could play with some of the text functions in the spss macro language (see second example).
If you have a longer list you can use a loop (like in the third example) to select the specific item you need in the list.
DEFINE !testMacro (factors = !ENCLOSE('(',')'))
title 'looping through all factors'.
!do !i !in(!factors)
title !quote(!i) .
!doend
title 'selecting third factor only'.
!let !fac3=!head(!tail(!tail(!factors)))
title !quote(!fac3) .
title 'selecting third with a loop'.
!let !facs=!factors
!do !i=1 !to 2
!let !facs=!tail(!facs)
!doend
!let !fac3=!head(!facs)
title !quote(!fac3) .
!enddefine.
!testMacro factors=(Aaa Bbb Ccc Ddd Eee Fff).
looping through all factors
Aaa
Bbb
Ccc
Ddd
selecting third factor only
Ccc
selecting third with a loop
Ccc

Related

How to read a specific part of a string?

Essentially, what I need is to read a certain part of a string.
Example:
I have a string that contains "12 31".
However, I need to put these numbers into separate variables. Just sorts 12 into lets say variable A, and 31 in variable B.
How should I go about this?
You can use Lua Patterns:
> ExampleString = "12 31"
> ExampleString:match("(%d+)%s+(%d+)")
12 31
> SubString1, SubString2= ExampleString:match("(%d+)%s+(%d+)")
> Number1 = tonumber(SubString1)
> Number2 = tonumber(SubString2)
The Pattern expression seems complex but is actually quite simple. The things between ( and ) are named captures and will be returned if they are found. Here, we want 2 results so we have 2 couples ( and ). %d+ means that we want to find a string which contains at least 1 digit (+).
The 2 numbers are separated by some spaces %s+, at least 1 (+).
In summary, we want to extract (Number1)space(Number2)
The function string.match is used to match against the given pattern and returns the found strings. The last step is to use the function tonumber to convert the found sub-strings into Lua numbers.

Systematically renaming variables in SPSS (without Python)

I'm looking for a solution to rename variables in SPSS. I can't use Python because of software restrictions at my workplace.
The goal is to rename variables into "oldname_new".
I tried "do repeat" like this, but it can't be combined with the rename function.
do repeat x= var1 to var100.
rename var (x=concat("x","_new")).
end repeat print.
exe.
Also, I figured that even without the do repeat, the rename command doesn't allow concat and similar commands? Is that correct?
So, is there any solution for this in SPSS?
As you found out you can't use rename within a do repeat loop.
SPSS macro can do this -
define DoNewnames ()
rename vars
!do !v=1 !to 100 !concat("var", !v, " = var", !v, "_new") !doend .
!enddefine.
* now the macro is defined, we can run it.
DoNewnames .
EDIT:
The code above is good for a set of variables with systematic names. In case the names are not systematic, you will need a different macro:
define DoNewnames (varlist=!cmdend)
rename vars
!do !v !in(!varlist) !concat(!v, " = ", !v, "_new") !doend .
!enddefine.
* Now in this case you need to feed the variable list into the macro.
DoNewnames varlist = age sex thisvar thatvar othervar.
If you want to see the syntax generated by the macro (like you did with end repeat print) you can run this before running the macro:
set mprint on.
EDIT 2:
As the OP says - the last macro requires naming all the variables to be renamed, which is a hassle if there are many. So the next code will get them all automatically without naming them individually. The process - as described in #petit_dejeuner's comment - creates a new data set that contains each original variable as an observation, and the original variable name as a value (=meta information about the variables, like a codebook). This way, you can recode the variable name into the renaming syntax.
dataset name orig.
DATASET DECLARE varnames.
OMS /SELECT TABLES /IF COMMANDS=['File Information'] SUBTYPES=['Variable Information']
/DESTINATION FORMAT=SAV OUTFILE='varnames' VIEWER=NO.
display dictionary.
omsend.
dataset activate varnames.
string cmd (a50).
compute cmd=concat("rename vars ", rtrim(var1), " = ", rtrim(var1), "_new .").
* Before creating the rename syntax in the following line, this is your chance to remove variables from the list which you do not wish to rename (using "select if" etc' on VAR1).
write out="my rename syntax.sps" /cmd.
dataset activate orig.
insert file="my rename syntax.sps" .
A couple of notes:
Before writing to (and inserting from) "my rename syntax.sps" you may need to add a writable path in the file name.
This code will rename ALL the variable in the dataset. If you want to avoid some of the variables - you should filter them in the variable list before writing out to "my rename syntax.sps" (see where I point this out in the code).

Lua Pattern, problem for combination handle

I want to capture some strings, but how come this is not working? I noticed that using [] it only detects each individual character, I wanted to know if it is possible with more characters
I want to take these combinations, but it's wrong
A ||
Z <<
O ~~~
O..
Current Code:
C = [[
A
B|
C<
Z<<
O~~~
O.
O..
]]
C = C:gsub("(\n%a[(||)(<<)(~~~)(%.%.%.)])",function(a)
print(a)
end)
Output:
B|
C<
Z<
O~
O.
O.
Your Pattern should be something like: (\n%a[|<~%.]+).
Placing a ( inside a lua pattern set just adds ( to the list of chars that could be matched it does not make a "sub-set" or force a required match length.
Lua patterns do not match multiple chars if repeated in a single set. to match multiple chars you need to use the +, * or use multiple instance of the set like this: (\n%a[|<~%.][|<~%.][|<~%.]).
Issues with this are that multiple instances of the set must all match, while if the + is used you have variability in the length of instances you could match such as one . rather than three.
You can not enforce granularity to match 2 different lengths of characters. By this, I mean you can not match specifically O<< and O~~~ in the same pattern while not matching O<<<, O~~ or O<<~.
Resources to learn more about Lua patterns:
FHUG - Understanding Lua Patterns

How would you parse this ingredient line?

I have a text area full of lines of ingredient; typically in a [quantity] [measurement] [ingredient] [additional] format. For example, a few ingredient lines might be:
1 tablespoon garlic, minced
1 cup bell pepper, chopped
I want to be able to identify each measurement and ingredient -- how would you process this? My line of thought was...
// loop thru line by line of textarea
// explode each line by the space thus line[0] would be 1, line[1] tablespoon, line[2] garlic... etc
Now here is my problem and I'm not sure what is efficient to do. Do I run each line[X] thru a db search for that measurement, ingredient, etc? But since "bell pepper" is separated by a space, I won't get a match.
// does line[1] appear in the measurements table?
// does line[2] appear in the ingredients table?
anyone else have any creative solutions?
Separate your data not by space but another delimiter. For example you could do:
$strRecipe = "1 | tablespoon | bell pepper | minced";
And then you can use:
$recipe = explode("|",$strRecipe);
Now you can access each field by: $recipe[0], $recipe[1] ETC ETC
Try stripos() to locate substring instead of explode().
$mytext = "1 tablespoon garlic, minced 1 cup bell pepper, chopped"; # or any text
$keyword = "bell pepper"; # or any search term
if (stripos($mytext, $keyword) === false) {
# not found
...
}
else {
# found
...
}
References
stripos() - case-insensitive search
strpos() - case-sensitive search
You can use explode() (not recommended) but than also you should separate words in your search term and look for an occurrence of first keyword in array where next keyword follows in next element of array, etc. It's unnecessary complication.

Can you iterate in LaTeX?

I'm new to LaTeX and I must say that I am really struggling with it. I discovered the \newcommand command that is kind of like a function/method in regular programming languages. You can give it arguments and everything.
I was wondering though, can I somehow iterate in LaTeX? Basically, what I would like to do is create a table with N+1 columns where the first row just contains a blank cell and then the numbers 1, 2, ..., N in the other columns. I only want to give N as an argument to this 'function' (newcommand).
Here is an example of something that might look like what I'm looking for (although obviously this won't work):
\newcommand{\mytable}[2]{
\begin{tabular}{l|*{#1}{c|}} % table with first argument+1 columns
for(int i = 1; i <= #1; i++) "& i" % 'output' numbers in different columns
\\\hline
letters & #2 % second argument should contain actual content for row
\\\hline
\end{tabular}
}
Call it with:
\mytable{3}{a & b & c}
Output should be:
| 1 | 2 | 3 |
--------+---+---+---+
letters | a | b | c |
--------+---+---+---+
Does anyone know if something like this is possible?
Thanks!
Just make the following into a new command and be sure to use package ifthen.
\begin{tabular}{l|*{10}{c|}}
\newcounter{count}
\whiledo{\value{count}<10}{
\ifthenelse{\value{count}=0}{}{\the\value{count}}
\ifthenelse{\value{count}<9}{&}{\\}
\stepcounter{count}
}
letters&a&b&c&d&e&f&g&h&i\\
\end{tabular}
Auntie Google says yes.
You can use the \loop or \repeat tokens. Or the multido package.
Sure it's possible. You can also recur. eplain has iteration macros in it, see, eg, here.
Another possibility (if you're lazy like me) is perltex

Resources