How do I Display an Array in Human Readable Form?

This lesson describes how to implement a short recursive algorithm to display arbitrarily nested arrays that contain printable data. Sample code is provided.

Introduction

It is often convenient to represent complex data sets as nested array structures. This allows information to be grouped in a logical form that is easily accessible from within a LiveCode application. As the data of such an array structure grows, it can quickly become difficult for a human reader to interpret the data and determine the array structure. Fortunately, it is very easy to write a generic function that decomposes complex array structures into an easily readable form.

Creating the Array Data

The structure and depth of the array can be chosen freely to meet the requirements of the data that is to be stored.

In the following example, the data represents an arrangement that may be present in an application that is used to process purchases of online book orders.

The data stored contains: The first name, the last name, the country in which the customer lives, the books a customer purchased, the currency in which the books were paid for and the payments that were made for each book. In this example, the book seller allows for books to be paid for in instalments.

# declare the variable that stores the array
local tCustomerDataArray
# populate the customer names
put "John" into tCustomerDataArray["1"]["address"]["first_name"]
put "Smith" into tCustomerDataArray["1"]["address"]["last_name"]
put "Peter" into tCustomerDataArray["2"]["address"]["first_name"]
put "Brown" into tCustomerDataArray["2"]["address"]["last_name"]
put "Martin" into tCustomerDataArray["3"]["address"]["first_name"]
put "Adamson" into tCustomerDataArray["3"]["address"]["last_name"]
put "Julia" into tCustomerDataArray["4"]["address"]["first_name"]
put "King" into tCustomerDataArray["4"]["address"]["last_name"]

# populate the customer country details
put "Scotland" into tCustomerDataArray["1"]["address"]["country"]
put "Germany" into tCustomerDataArray["2"]["address"]["country"]
put "England" into tCustomerDataArray["3"]["address"]["country"]
put "Sweden" into tCustomerDataArray["4"]["address"]["country"]

# populate the customer order details
put "Walking in Scotland" into tCustomerDataArray["1"]["orders"]["1"]["book"]
put "The Great Outdoors" into tCustomerDataArray["1"]["orders"]["2"]["book"]
put "Kilts and Stuff" into tCustomerDataArray["1"]["orders"]["3"]["book"]
put "1001 Jokes" into tCustomerDataArray["2"]["orders"]["1"]["book"]
put "Makeup and Fashion" into tCustomerDataArray["3"]["orders"]["1"]["book"]
put "Meat Ball Recipes" into tCustomerDataArray["4"]["orders"]["1"]["book"]
put "Ice Hotels DIY" into tCustomerDataArray["4"]["orders"]["2"]["book"]

# populate the customer payments
put "pounds" into tCustomerDataArray["1"]["orders"]["1"]["currency"]
put "10.00" into tCustomerDataArray["1"]["orders"]["1"]["payments"]["1"]
put "pounds" into tCustomerDataArray["1"]["orders"]["2"]["currency"]
put "15.00" into tCustomerDataArray["1"]["orders"]["2"]["payments"]["1"]
put "pounds" into tCustomerDataArray["1"]["orders"]["3"]["currency"]
put "7.00" into tCustomerDataArray["1"]["orders"]["3"]["payments"]["1"]
put "7.00" into tCustomerDataArray["1"]["orders"]["3"]["payments"]["2"]
put "euro" into tCustomerDataArray["2"]["orders"]["1"]["currency"]
put "5.00" into tCustomerDataArray["2"]["orders"]["1"]["payments"]["1"]
put "5.00" into tCustomerDataArray["2"]["orders"]["1"]["payments"]["2"]
put "pounds" into tCustomerDataArray["3"]["orders"]["1"]["currency"]
put "20.00" into tCustomerDataArray["3"]["orders"]["1"]["payments"]["1"]
put "krona" into tCustomerDataArray["4"]["orders"]["1"]["currency"]
put "12.00" into tCustomerDataArray["4"]["orders"]["1"]["payments"]["1"]
put "krona" into tCustomerDataArray["4"]["orders"]["2"]["currency"]
put "17.00" into tCustomerDataArray["4"]["orders"]["2"]["payments"]["1"]   

This array represents the information of four customers and their purchases.

Decomposing the Array Data

There are potentially many ways of decomposing array data into a human readable form, and the representation chosen depends on personal preference and the data structure that is to be displayed.

The code in this lesson is generic and can be used on a large range of arrays. Data is processed in two ways:

1. Indent the data from left to right, depending on the depth at which the data is stored in the array.

2. Group information together depending on how close it lies together in the array structure.

function displayArrayData pArray, pIndent
	# create the variable that loops through the keys in the array
	local tKey
	if pArray is an array then
		# print information to indicate that we are entering a new nested level of the array
		get "Array" & return
		# print full stops that allow the reader to track the depth of an element
		put "." after pIndent
		# create the indentation
		put tab after pIndent
		repeat for each key tKey in pArray
			# call displayArrayData with a nested array
			put format("%s[%s] => %s\n", pIndent, tKey, displayArrayData (pArray[tKey], pIndent)) after it
		end repeat
		delete the last char of it
		return it
	else
		return pArray
	end if 
end displayArrayData

The level of indentation and its formatting is explicitly controlled by output lines in the function. Information grouping is implicitly generated as a result of  depth-first search exploration of the array data structure.

Executing the Function and Displaying the Data

To execute the function and display the result in the Message Box you can execute

put displayArrayData(tCustomerDataArray,".")

To execute the function from a button and display the result in a field you can call the function from a mouseUp handler.

on mouseUp

   // Construct the array data in tCustomerDataArray

   put displayArrayData(tCustomerDataArray,".") into field "readableDisplay"

end mouseUp

The Formatted Output

The output from displayArrayData is written to the LiveCode Message Box and is structured as follows:

Array

. [1] => Array

. . [address] => Array

. . . [first_name] => John

. . . [last_name] => Smith

. . . [country] => Scotland

. . [orders] => Array

. . . [1] => Array

. . . . [payments] => Array

. . . . . [1] => 10.00

. . . . [book] => Walking in Scotland

. . . . [currency] => pounds

. . . [2] => Array

. . . . [payments] => Array

. . . . . [1] => 15.00

. . . . [book] => The Great Outdoors

. . . . [currency] => pounds

. . . [3] => Array

. . . . [payments] => Array

. . . . . [1] => 7.00

. . . . . [2] => 7.00

. . . . [book] => Kilts and Stuff

. . . . [currency] => pounds

. [2] => Array

. . [address] => Array

. . . [first_name] => Peter

. . . [last_name] => Brown

. . . [country] => Germany

. . [orders] => Array

. . . [1] => Array

. . . . [payments] => Array

. . . . . [1] => 5.00

. . . . . [2] => 5.00

. . . . [book] => 1001 Jokes

. . . . [currency] => euro

. [3] => Array

. . [address] => Array

. . . [first_name] => Martin

. . . [last_name] => Adamson

. . . [country] => England

. . [orders] => Array

. . . [1] => Array

. . . . [payments] => Array

. . . . . [1] => 20.00

. . . . [book] => Makeup and Fashion

. . . . [currency] => pounds

. [4] => Array

. . [address] => Array

. . . [first_name] => Julia

. . . [last_name] => King

. . . [country] => Sweden

. . [orders] => Array

. . . [1] => Array

. . . . [payments] => Array

. . . . . [1] => 12.00

. . . . [book] => Meat Ball Recipes

. . . . [currency] => krona

. . . [2] => Array

. . . . [payments] => Array

. . . . . [1] => 17.00

. . . . [book] => Ice Hotels DIY

. . . . [currency] => krona

The data is logically grouped, and the data depth is indicated by the number of full stops in front of each entry. For example, address data contains the first_name, the last_name and the country.

Note: If you do not know how the grouping was created or mapped to the array, please refer to the source array structure and compare it to the output that is shown here.

7 Comments

Dennis Wurster

Can you provide the syntax of your function call?

In the case of the article, I'm expecting it to be something like

displayArrayData tCustomerDataArray, "."

and I'd expect the full line of code to be something like

put displayArrayData tCustomerDataArray, "." into field "results"

Elanor Buchanan

Hi Dennis

You call a function in LiveCode like this:

displayArrayData(tCustomerArrayData,".")

the full line of code would be

put displayArrayData(tCustomerArrayData,".") into field "results"

In this case you don't actually need to pass pIndent when you first call the function, pIndent is used when the function is called recursively but can be left empty in the initial call.

I hope that helps.

Elanor

Rachel

Hi Elanor,

This lesson needs a little TLC on your end. It gave me quite a bit of trouble before I finally realized what was happening.

As a beginner to LC, I didn't understand that in order to call the code from a button or message box, I would have to use the "put" command in front of the function call. I also attempted to use your function call in the code. It took me quite a while to notice that your call was actually different from the code provided. I believe the correct function call should be as follows:

put displayArrayData (tCustomerDataArray), "." into field "results"

I know that you are very busy, but I wonder if other beginners might benefit from a little more code in the example. Then, when they run it from an object, they wouldn't have to troubleshoot quite as much.

I'm enjoying LiveCode. Thank you for all of your hard work.
-Rachel

Elanor Buchanan

Dear Rachel,

Thank you for your kind and helpful comments. I have added a section that explains more about how to execute the code, and I have also added an example stack that can be downloaded and run. I hope that will make things a bit clearer and easier for less experienced LiveCode users.

I'm glad you hear you are enjoying LiveCode!

Kind regards

Elanor

Gil

hello Elanor,

Thank you for this example.

However, the order in the output is not chronological.
For example, instead of 1,2,3, you see 1,3,2

How can I solve this?

Thank you and best regards
Gil

Elanor Buchanan

Hi Gil

The reason for this is that the keys of an array are not returned ordered. If the order is important you can get the keys, sort them then loop across the ordered keys.

Something like this

...
put the keys of pArray into tKeys
if line 1 of tKeys is a number then
sort lines of tKeys ascending numeric
else
sort lines of tKeys ascending
end if

repeat for each line tKey in tKeys
# call displayArrayData with a nested array
put format("%s[%s] => %s\n", pIndent, tKey, displayArrayData (pArray[tKey], pIndent)) after it
end repeat
...

I hope that helps.

Elanor

Gil

hi Elanor,
thanks a lot for your quick help!
It helped me alot!

Thank you and best regards
Gil

Add your comment

E-Mail me when someone replies to this comment