How to Iterate un even Multi Dimensional Array global Programmatically
Hi Community,
I have created global with below values , now I want to iterate programatically.
^Book("Auto1","Properties","Color")="Red"
^Book("Auto1","Properties","Color1")="Yellow"
^Book("Auto1","Properties","Model")="SUV"
^Book("Auto2","Owner")="Prashanth"
^Book("Auto2","Properties","Color")="Green"
^Book("Color")="Red"
^Book("Color1")="Red"
i have used below method but only printing last2 elements properly
ClassMethod Iterate()
{
set subscript = ""
for {
set subscript = $order(^Book(subscript))
quit:(subscript = "")
write !, "subscript=", subscript, ", value=", ^Book(subscript)
}
}
Thanks,
Prashanth
Comments
$ORDER() always operates at the distinct subscript level you start it Auto1,Auto2, Color,Color2
to check for a deeper level you may use $DATA()
or you run your search using $QUERY() which returns only instances with data
Hi.
You should use function $QUERY ($QUERY | ObjectScript Reference | InterSystems IRIS Data Platform 2020.1
).
Regards,
Matjaž
Well, everyone has coding styles and ObjectScript offers several different styles - I could have made this prettier (to me, anyway) as I'm more accustomed to the single-letter-command and dot-loop styles... but I tried to keep this in your coding style.
My code isn't pretty - I focused more on making it (barely) functional and demonstrative of the $DATA command - this command will let you know if there's any further subscripts available in a global - documentation page is here:
https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_FDATA
Anyway, here's my code - I didn't have a chance to create a class method (again, I prefer the older styles) but just copy-paste the code center into your method and it should function. Again, it's not pretty, but it will demonstrate what you need.
If you wanted to make this more efficient, recoding this to handle subscripts recursively would be much shorter and could handle any number of subscripts, not just 3.
ZSUBFINDER ;
;
set subscript = ""
for {
set subscript = $order(^Book(subscript))
quit:(subscript = "")
set moresub = $data(^Book(subscript))
if moresub=10 {
set sub2=""
for {
set sub2 = $order(^Book(subscript,sub2))
quit:(sub2="")
set moresub2= $data(^Book(subscript,sub2))
if moresub2=10 {
set sub3=""
for {
set sub3 = $order(^Book(subscript,sub2,sub3))
quit:(sub3="")
set moresub3= $data(^Book(subscript,sub2,sub3))
if moresub3 = 1 {
write !, "subscript=", subscript, ", sub2=", sub2, ", sub3=", sub3, ", value=", ^Book(subscript,sub2,sub3)
}
}
} else {
if moresub2=1 {
write !, "subscript=", subscript, ", sub2=", sub2, ", value=", ^Book(subscript,sub2)
}
}
}
} else {
if moresub=1 {
write !, "subscript=", subscript, ", value=", ^Book(subscript)
}
}
}
quitHope this helps!
Thanks a lot, Roger, yes working fine.
thanks for your time and effort to share the code snippet.
How this one can be turned into recursive?
I have no idea how to create programatically to check level deeper and deeper and so on.
ClassMethod array2xml(array) As%String
{
SET subscript = ""FOR
{
SET subscript = $ORDER(array(subscript))
QUIT:subscript=""SET dataStatus = $DATA(array(subscript)),
currentRef = array(subscript)
write !, "Subscript=", subscript_", Value=", currentRef_" DataStatus: "_dataStatus
IF (dataStatus > 9)
{
SET a = ""MERGE arr = array(subscript)
// More subscripts, go deeperK DO..array2xml(.arr)
}
ELSEIF (dataStatus = 1)
{
// No more subscripts, just a value
}
}
}Problem is that my output start repeating. Here is example array
SET array(1) = "1",
array(1,1) = "1,1",
array(1,1,1) = "1,1,1",
array(1,1,2) = "1,1,2",
array(1,1,3) = "1,1,3",
array(1,1,1,1) = "1,1,1,1",
array(2) = "2",
array(2,1) = "2,1",
array(2,1,1) = "2,1,1"And here are the output
Subscript=1 Value=1 DataStatus: 11
Subscript=1 Value=1,1 DataStatus: 11
Subscript=1 Value=1,1,1 DataStatus: 11
Subscript=1 Value=1,1,1,1 DataStatus: 1
Subscript=2 Value=1,1,2 DataStatus: 1
Subscript=3 Value=1,1,3 DataStatus: 1
Subscript=2 Value=2 DataStatus: 11
Subscript=1 Value=2,1 DataStatus: 11
Subscript=1 Value=2,1,1 DataStatus: 11
Subscript=1 Value=1,1,1,1 DataStatus: 1
Subscript=2 Value=1,1,2 DataStatus: 1
Subscript=3 Value=1,1,3 DataStatus: 1
I think I figgured out by adding KILL array(subscript) right after MERGE arr
Subscript=1 Value=1 DataStatus: 11
Subscript=1 Value=1,1 DataStatus: 11
Subscript=1 Value=1,1,1 DataStatus: 11
Subscript=1 Value=1,1,1,1 DataStatus: 1
Subscript=2 Value=1,1,2 DataStatus: 1
Subscript=3 Value=1,1,3 DataStatus: 1
Subscript=2 Value=2 DataStatus: 11
Subscript=1 Value=2,1 DataStatus: 11
Subscript=1 Value=2,1,1 DataStatus: 1
In the...good old days, we used to do that in one line 😂
s node="array" f s node=$q(@node) q:node="" w node,"=",@node,!
array(1)=1
array(1,1)=1,1
array(1,1,1)=1,1,1
array(1,1,1,1)=1,1,1,1
array(1,1,2)=1,1,2
array(1,1,3)=1,1,3
array(2)=2
array(2,1)=2,1
array(2,1,1)=2,1,1
That approuch I was trying, but I got always an error of undefined so I gave up.
ClassMethod test(array)
{
SET value = ""FOR
{
SET value = $QUERY(@array)
QUIT:value=""W value,"=",@array,!
}
QUIT
}
DO##class(intranet.util.xml).test(.a)
<UNDEFINED>test+4^intranet.util.xml.1 *array$query argument can be a global or a public variable, so when using local variable array change the method signature:
ClassMethod test(array) [ public= array ]
Or use a temp global or, even better, a Process Private Global instead.
I dont know what Im missing here but its not work at all with $QUERY and @ indirection. Still is undefined even I converted local varaible into process private global.
Method setLayout(layout) As%Status
{
MERGE ^||layout = layout
SET node = ""FOR
{
SET node = $QUERY(@^||layout)
QUIT:node=""W node,"",@node,!
}
QUIT$$$OK
}Obviously I was still trying to apply pattern from $ORDER . This one works.
SET node = $QUERY(^||layout(""))
WHILE (node '= "")
{
W !, node
SET node = $QUERY(@node)
}Using Process Private Global:
ClassMethod setLayout(layout) As%Status
{
MERGE ^||layout = layout
Set node="^||layout"For {
Set node=$query(@node) Q:node=""Write node,"=",@node,!
}
Quit$$$OK
}Using local variable array:
ClassMethod arrayQuery(myArrayLocalName) [ PublicList = myArrayLocalName ]
{
Set node="myArrayLocalName"For {
Set node=$query(@node) Q:node=""Write node,"=",@node,!
}
}
Note: the idea of using Process Private Global was INSTEAD of local variable array all around, not merging etc.