Hello everyone —
I’m trying to set up an index loop (https://www.ibm.com/support/knowledgecenter/en/SSLVMB_24.0.0/spss/base/syn_define_index_loop.html#syn_define_index_loop).
The tricky thing is that the finish value isn’t constant, so I need to specify it with a macro.
So instead of:
!DO !integer = 1 !TO 2
!DOEND
I need something like:
!DO !integer = 1 !TO @AnyInteger
!DOEND
Coupled with
DEFINE @SomeInteger() 2 !ENDDEFINE.
As you’ll see below, however, this doesn’t work. Even though @SomeInteger is an integer, SPSS doesn’t recognize it as such.
I’ve provided all my syntax and relevant output below.
Any workarounds would be greatly appreciated.
Thanks in advance.
— Jeff
* read in a bogus case of case.
DATA LIST LIST /a .
BEGIN DATA
1
END DATA.
* set up a simple Index Loop the regular way (https://www.ibm.com/support/knowledgecenter/en/SSLVMB_24.0.0/spss/base/syn_define_index_loop.html#syn_define_index_loop).
* the finish value is an actual number (2).
define @IndexLoop1 ()
!DO !integer = 1 !TO 2
compute b = !integer .
!DOEND
exe.
!enddefine.
@IndexLoop1.
* set up an Index Loop in which the finish value is a macro that has a value of "2".
define @SomeInteger() 2 !enddefine.
define @IndexLoop2 ()
!DO !integer = 1 !TO @SomeInteger
compute c = !integer .
!DOEND
!enddefine.
@IndexLoop2.
* Output I receive:
* >Warning # 228
* >Invalid string found where numeric value required in macro expression.
* >Warning # 221
* >Macro expansion found an error interpreting an operation code. Check the
* >arguments to functions and loop parameters for valid values.
* 4123 0 M> !ERROR_MACRO
* >Error # 1. Command name: !ERROR_MACRO
* >The first word in the line is not recognized as an SPSS Statistics command.
* >Execution of this command stops.
* 4124 0 M> .
**********************
Jeff T. Larsen, Ph.D. Professor of Psychology University of Tennessee, Knoxville [hidden email] / 865-974-9967 |
Within the same macro, !a and !b are defined as you like,
for example
!if (......) !then !let !a=1 !let !b=2 !else !let !a=0 !let !b=15 !ifend !do !i= !a !to !b ...... !doend If you want them to be external short macros, such as define !a() 1 !enddefine define !b() 2 !enddefine Then use !eval function to expand the macro names in the body of the main macro !do !i= !eval(!a) !to !eval(!b) ...... !doend ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
Kirill — Thanks so much! — Jeff
**********************
Jeff T. Larsen, Ph.D. Professor of Psychology University of Tennessee, Knoxville [hidden email] / 865-974-9967
From: Kirill Orlov <[hidden email]>
Reply-To: Kirill Orlov <[hidden email]> Date: Saturday, January 13, 2018 at 9:00 AM To: "[hidden email]" <[hidden email]> Subject: Re: index loops: any way to use macros to supply finish values? Within the same macro, !a and !b are defined as you like, for example
!if (......) !then !let !a=1 !let !b=2 !else !let !a=0 !let !b=15 !ifend !do !i= !a !to !b ...... !doend If you want them to be external short macros, such as define !a() 1 !enddefine define !b() 2 !enddefine Then use !eval function to expand the macro names in the body of the main macro !do !i= !eval(!a) !to !eval(!b) ...... !doend ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
Administrator
|
Please describe what you are actually trying to achieve.
Maybe what you need to do can be done with a simple LOOP without Macro? If you are just using Transformations and not iterating with procedures the LOOP will do just fine. It can even use data values within a case to build the result -NOT doable with MACRO- ----- Please reply to the list and not to my personal email. Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" -- Sent from: http://spssx-discussion.1045642.n5.nabble.com/ ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
In reply to this post by Larsen, Jeff T
Regardless of specifics, it is likely a preferred solution
to pass the macro parameters rather than have your syntax be tainted by global elements which require upkeep. ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
Administrator
|
Example:
DEFINE !MacroWithArgs (!POS !TOKENS(1) / !POS !TOKENS(1) ) ECHO !QUOTE(!1). ECHO !QUOTE(!2). !ENDDEFINE. !MacroWithArgs 3 2 . OR DEFINE !MacroWithNamedArgs (A !TOKENS(1) / B !TOKENS(1) ) ECHO !QUOTE(!A). ECHO !QUOTE(!B). !ENDDEFINE. !MacroWithNamedArgs A=3 B=2. ----------------------------- VS This virtually unmaintainable monstrosity: DEFINE !A () 3 !ENDDEFINE. DEFINE !B() 2 !ENDDEFINE. DEFINE DoSomethingStupid () ECHO !EVAL(!A). ECHO !EVAL(!B). !ENDDEFINE. DoSomethingStupid . ----- Please reply to the list and not to my personal email. Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" -- Sent from: http://spssx-discussion.1045642.n5.nabble.com/ ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
In reply to this post by David Marso
Thanks, David.
Kirill Orlov answered my specific question by referring me to !EVAL. This
worked perfectly, but I agree that it would be better to avoid generating a macro.
Here’s what happens: In the context of a bigger (and definitely unavoidable) macro, I loop through a !DO-!DOEND loop dozens (if not hundreds) of times. During each loop, I process data from different
subsets of cases (using FILTER BY). At the end of each loop, I save the output to an SPV file that is named on the basis of values of SPSS variables that identify that particular subset of cases.
That said, I’m intrigued by this: “[LOOP] can even use data values within a case to build the result -NOT doable with MACRO” because it was precisely
this limitation of macros that prompted my question.
Have I given you enough details?
— Jeff
**********************
Jeff T. Larsen, Ph.D. Professor of Psychology University of Tennessee, Knoxville [hidden email] / 865-974-9967
From: David Marso <[hidden email]>
Reply-To: David Marso <[hidden email]> Date: Monday, January 15, 2018 at 3:19 PM To: "[hidden email]" <[hidden email]> Subject: Re: index loops: any way to use macros to supply finish values? Please describe what you are actually trying to achieve.
Maybe what you need to do can be done with a simple LOOP without Macro?
If you are just using Transformations and not iterating with procedures the
LOOP will do just fine.
It can even use data values within a case to build the result -NOT doable
with MACRO-
-----
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me.
---
"Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis."
Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?"
--
=====================
To manage your subscription to SPSSX-L, send a message to
[hidden email] (not to SPSSX-L), with no body text except the
command. To leave the list, send the command
SIGNOFF SPSSX-L
For a list of commands to manage subscriptions, send the command
INFO REFCARD
|
Administrator
|
"During each loop, I process data from different subsets of cases (using
FILTER BY). " How are the filters generated? Are they dynamically data driven or are they specific conditions which can be listed? FWIW: You can't do OUTPUT SAVE within a transformation LOOP so basic LOOP is not the solution. You can't acquire case level data values to use a !DO !DOEND block. This might be a job for the SPSSINC SPLIT DATA SETS and SPSSINC PROCESS FILES extensions. You can search in this group for examples. OTOH: Please post the specifics of the filter generation methodology, it may be amenable to a MACRO or a python-MACRO hybrid solution. ----- Please reply to the list and not to my personal email. Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" -- Sent from: http://spssx-discussion.1045642.n5.nabble.com/ ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
In reply to this post by Larsen, Jeff T
Hi David —
I was able to get a pretty clean macro that works perfectly, so I’m in good shape. Thanks for pointing me toward SPSSINC PROCESS FILES. That would have saved a lot of time!
You’ve already answered my question, but here are answers to yours anyway. I’m reluctant to include my code because there’s a lot going on and it calls a lot of homegrown macros that are defined elsewhere, but I’ve pasted it below (I begin macro names
with @).
How are the filters generated? Are they dynamically data driven or are they
specific conditions which can be listed?
Dynamically data driven. The macro figures out how many “case clusters” there are (CaseClusterCount), where each case cluster represents all the cases with a given combination of values of a handful of filter variables (which
are specified with !FilterVarList ).
FWIW: You can't do OUTPUT SAVE within a transformation LOOP so basic LOOP is not the solution.
Yes. That would have been nice! I do it at the end of a !DO !DOEND block instead.
You can't acquire case level data values to use a !DO !DOEND block.
Yes. That’s where what I believe Raynald would call “self adjusting code” comes in. After counting up the case clusters, I write that integer to a macro. See the blue portion below. That value later serves as the FINISH
value in my !DO !DOEND block.
This might be a job for the SPSSINC SPLIT DATA SETS and SPSSINC PROCESS FILES extensions.
This was definitely a case for SPSSINC PROCESS FILES. Now I know for next time.
Thanks again.
— Jeff
define @FasoLoop1 (analysis = !charend('|') /study = !charend('|') /AnalysisCommands = !charend('|') /FilterVarList = !enclose('[',']')
/PathVarList = !enclose('[',']') /FileVarList = !enclose('[',']') /CaseClusterCount = !charend('|')
/SuppressSaveOutput = !charend('|') )
@CloseAllBut mothership.
use all.
* select if this case is from the specified study .
select if study$ = !quote ( !study ) .
* select if this case is eligible for the analysis.
!if ( !analysis = wilco ) !then
select if nvalid (RelBad99, RelGud99) = 2 .
!ifend
* enumerate the case clusters .
@EnumerateCaseClusters dataset = mothership | BreakVarList = [ @FilterVarList ] BreakVarListName = FilterVar | BreakVarCount = 6 .
dataset activate CaseClusters .
@SaveOut !quote(!concat ( 'sav/ForAnalyses/' , !analysis , '_', !study, '_CaseClusters.sav' ))
* generate a macro containing the number of case clusters.
sort cases by CaseClusterNum (d).
if $casenum = 1 WriteCaseToSps = 1 .
!let !CaseClusterCountMacro = !concat ( !analysis , '_', !study, '_CaseClusterCount' )
@MacroMaker MacroName = !CaseClusterCountMacro | MacroVar = CaseClusterNum | IncludeMacro = 1 .
sort cases by CaseClusterNum (a).
* for the first case in each case cluster, build up OutputPath$ and OutputFile$.
@CloseAllBut mothership .
string OutputPath$ OutputFile$ (a100).
do if NewCaseCluster = 1 .
compute OutputPath$ = !quote (!concat ( !analysis , '/' , !study , '/' ) ).
!do !p !in ( !PathVarList )
compute OutputPath$ = concatenate (OutputPath$, !p, '/') .
!doend
compute OutputFile$ = !quote( !concat( !analysis, '_' , !study )) .
!do !f !in ( !FileVarList )
compute OutputFile$ = concatenate (OutputFile$, '_', !f ) .
!doend
compute OutputFile$ = concatenate (OutputFile$, '_CaseCluster', replace ( string ( CaseClusterNum, f4.0), ' ', '0') ) .
end if.
* specify TableList as a function of analysis, then launch OMS.
!if ( !analysis = wilco ) !then !let !TableList = 'WilcoDiffs WilcoTests' !ifend
@OmsTable0_Launch TableList = [ !TableList ]
* proceed through the loops.
!do !cc = 1 !to !eval ( !concat ( '@', !CaseClusterCountMacro ))
* filter out all cases except those from the current CaseCluster.
compute keep = CaseClusterNum = !cc .
filter by keep .
* do analysis (note: !analysis commands will probably be a macro) .
!AnalysisCommands .
* retrieve OutputPath$ and OutputFile$ from the first row of this case cluster and write them to separate temporary macros.
if ( keep and NewCaseCluster ) WriteCaseToSps = 1 .
@MacroMaker MacroName = TmpOutputPath | MacroVar = OutputPath$ | IncludeMacro = 1 .
@MacroMaker MacroName = TmpOutputFile | MacroVar = OutputFile$ | IncludeMacro = 1 .
@DelVar WriteCaseToSps .
* save the output file (pulling the TmpOutputPath and TmpOutputFiles that were just generated) .
*@*SaveOutput suppress = !SuppressSaveOutput | path = @TmpOutputPath | file = @TmpOutputFile | CloseOutput = 0.
!doend
* clean up the mothership.
@DelVar NewCaseCluster CaseClusterNum OutputPath$ OutputFile$.
filter off.
* wrap up the OMS tables.
* end commands.
@OmsTable1_End TableList = [ !TableList ] .
* save OMS spawn.
!do !t !in ( !TableList )
@ConvertTableNumToClusterNum .
@SaveOut !quote(!concat( 'sav/oms/InPrep/', !analysis, '_', !study, '_', !t , '1.sav' )).
!doend
!enddefine.
**********************
Jeff T. Larsen, Ph.D. Professor of Psychology University of Tennessee, Knoxville [hidden email] / 865-974-9967
From: David Marso <[hidden email]>
Reply-To: David Marso <[hidden email]> Date: Tuesday, January 16, 2018 at 2:14 PM To: "[hidden email]" <[hidden email]> Subject: Re: index loops: any way to use macros to supply finish values? "During each loop, I process data from different subsets of cases (using
FILTER BY). "
How are the filters generated? Are they dynamically data driven or are they
specific conditions which can be listed?
FWIW:
You can't do OUTPUT SAVE within a transformation LOOP so basic LOOP is not
the solution.
You can't acquire case level data values to use a !DO !DOEND block.
This might be a job for the SPSSINC SPLIT DATA SETS and SPSSINC PROCESS
FILES extensions.
You can search in this group for examples.
OTOH: Please post the specifics of the filter generation methodology, it
may be amenable to a MACRO or a python-MACRO hybrid solution.
-----
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me.
---
"Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis."
Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?"
--
=====================
To manage your subscription to SPSSX-L, send a message to
[hidden email] (not to SPSSX-L), with no body text except the
command. To leave the list, send the command
SIGNOFF SPSSX-L
For a list of commands to manage subscriptions, send the command
INFO REFCARD
|
SPSSINC SPLIT DATASET and SPSSINC PROCESS FILES generalize the built-in SPLIT FILES procedure to allow any syntax to be executed iteratively over a set of data files. It is a little tricky to set up PROCESS FILES, but it can eliminate massive headaches. On Tue, Jan 16, 2018 at 1:01 PM, Larsen, Jeff T <[hidden email]> wrote:
|
Administrator
|
In reply to this post by Larsen, Jeff T
FWIW: One should avoid assigning macro names which are valid variable names.
@ is a valid first character for a variable name so you are opening a door to potential problems. The customary practice is to preceed the macro name with ! . That way one does not risk encountering collisions. ----- Please reply to the list and not to my personal email. Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" -- Sent from: http://spssx-discussion.1045642.n5.nabble.com/ ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
Free forum by Nabble | Edit this page |