Question
· Feb 24, 2022

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

Product version: IRIS 2022.1
Discussion (10)2
Log in or sign up to continue

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)
      }
      }
    }
 quit

Hope this helps!

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

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.