# Dictionary Key Order

**URL:** <https://forum.inductiveautomation.com/t/dictionary-key-order/63799>\
**Category:** Ignition\
**Tags:** ignition81, perspective\
**Created:** [September 6, 2022, 8:19pm UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799 "2022-09-06T20:19:13Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![aspatchek2013](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/aspatchek2013/32/85339_2.png) [@aspatchek2013](https://forum.inductiveautomation.com/u/aspatchek2013)\
**Post date:** [September 6, 2022, 8:19pm UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/1 "2022-09-06T20:19:13Z")

</div>

I have a view with a custom property which is running a named query and returning the data as JSON. Then I have another custom property which is referencing that JSON data and running a script transform to parse out only the columns that I need to show in a table. When I make my temp\_dict, I put the ‘Title’ key first and the ‘Details’ key second. However, when the script builds out the new dictionary, it reverses this order (The ‘Details’ key shows up before the ‘Title’ key). How can I write the script to make the temp\_dict maintain the key order that I enter?

 ![namedQuery](https://us1.discourse-cdn.com/inductiveautomation/original/3X/a/5/a5d49cd222b4595b7ea1a329bbd6c1f3d5f18046.png)

```auto
def transform(self, value, quality, timestamp):
	# Ignition formats JSON in a list
	json_list = []
	
	# If there is valid data, filter and create a new JSON list
	if value:
		for index, json_item in enumerate(value):
			temp_dict = {
				'Title':json_item['cr_title'],
				'Details':json_item['change_request']
				}
			json_list.append(temp_dict)
	# Otherwise add an empty entry to maintain table visual layout
	else:
		temp_dict = {
			'Title':'',
			'Details':''
			}
		json_list.append(temp_dict)
	
	# Return fitered data
	return json_list

```

**A few notes:**

1. In the interim, I have simply moved to using a dataset which I can order just fine. So I can get this to work. However, I’d still like to learn what I am doing wrong so I know for next time.
2. When I build a dictionary in Visual Studio, the key order is maintained in the order that I entered them. Visual Studio is running Python 3.10. I am aware of a Python change somewhere between version 2 and 3 that gave some order to dictionaries, so this could likely be a cause of this. However, I don’t understand that well enough at this point to know that it is the root cause of the differences I am seeing in results between the two different software platforms.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [September 6, 2022, 8:33pm UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/2 "2022-09-06T20:33:09Z")

</div>

You need `OrderedDict`.

[https://docs.python.org/2.7/library/collections.html#collections.OrderedDict](https://docs.python.org/2.7/library/collections.html#collections.OrderedDict)

> [@Ordered Dictionaries](https://forum.inductiveautomation.com/t/ordered-dictionaries/45949):
>
> Hi, I would like create a json file in a specific format, however there are some restriction involved. Declared dictionaries not in my specific key order (d,c,a,b). from collections import OrderedDict mylist = [] myOrderedDict = OrderedDict() myOrderedDict['d'] = 4 myOrderedDict['c'] = 3 myOrderedDict['a'] = 1 myOrderedDict['b'] = mylist myOrderedDict #Intended result dict(myOrderedDict) #dict changed my result myDict = {} myDict['d'] = 4 myDict['c'] = 3 myDict['a'] = 1 myDict['b'] = myl…

---

<div class="post-metadata">

**Author:** ![aspatchek2013](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/aspatchek2013/32/85339_2.png) [@aspatchek2013](https://forum.inductiveautomation.com/u/aspatchek2013)\
**Post date:** [September 6, 2022, 9:59pm UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/3 "2022-09-06T21:59:58Z")

</div>

Thanks Kevin - that is likely what I am looking for, but I am having an issue with it yet. In the script transform, it does not seem to perform as it does in the script console. It works as I would expect it to within the script console. See below.

 ![OrderedDictTransform](https://us1.discourse-cdn.com/inductiveautomation/original/3X/f/2/f282bf4d518187a4bd08e0e97e826cf57c4b1b9d.png)

 ![OrderedDictScriptConsole](https://us1.discourse-cdn.com/inductiveautomation/original/3X/e/c/ec9f52220fb66cb6d8740b896b10a7f27f778f3d.png)

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [September 6, 2022, 10:05pm UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/4 "2022-09-06T22:05:37Z")

</div>

I suspect Perspective’s JSON layer is using an unordered dictionary.

The answer for others with this specific problem is to define the table’s `columns` configuration, where each column is called out explicitly.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [September 6, 2022, 10:07pm UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/5 "2022-09-06T22:07:54Z")

</div>

Yeah, it looks like the ordering is lost after execution when the results get turned into a Java Map.

The `columns` configuration is the answer here, I didn’t read close enough to realize that.

---

<div class="post-metadata">

**Author:** ![aspatchek2013](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/aspatchek2013/32/85339_2.png) [@aspatchek2013](https://forum.inductiveautomation.com/u/aspatchek2013)\
**Post date:** [September 6, 2022, 10:10pm UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/6 "2022-09-06T22:10:18Z")

</div>

No problem. I will adjust the table column configuration (or simply leave it as a dataset). Thanks for teaching me something along the way!

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [September 6, 2022, 10:26pm UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/7 "2022-09-06T22:26:43Z")

</div>

FWIW, the table columns should probably always be configured regardless to give control over how they’re displayed, otherwise it may produce unexpected results at times

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [September 6, 2022, 10:51pm UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/8 "2022-09-06T22:51:38Z")

</div>

> [@aspatchek2013](#):
>
> I am aware of a Python change somewhere between version 2 and 3 that gave some order to dictionaries, so this could likely be a cause of this

Indeed, the implementation of dict changed in 3.6 (at least for Cpython ?). It made it keep keys in order, though it wasn't the goal - the new implementation focused on size and performance.  
On the other hand, OrderedDict's goal is to keep keys ordered.  
Here's what Raymond Hettinger (the new dict AND OrderedDict's father) has to say about it:

> **[\[Python-Dev\] Guarantee ordered dict literals in v3.7?](https://mail.python.org/pipermail/python-dev/2017-December/151266.html)**

Interesting dude, if you're interested about python.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [September 6, 2022, 11:25pm UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/9 "2022-09-06T23:25:54Z")

</div>

> [@pascal.fragnoud](#):
>
> Indeed, the implementation of dict changed in 3.6 (at least for Cpython ?). It made it keep keys in order, though it wasn’t the goal - the new implementation focused on size and performance.

As long as we're being pedantic: it is explicitly part of the language spec as of 3.7: [What’s New In Python 3.7 — Python 3.12.1 documentation](https://docs.python.org/3/whatsnew/3.7.html)

It's all somewhat immaterial to Ignition, though; besides being on Jython 2.7, in this context we're talking about (technically) JSON-like mapping structures, which happen to closely _resemble_ Python's dictionaries, but are explicitly order-agnostic.

---

<div class="post-metadata">

**Author:** ![jsorlie](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jsorlie/32/3645_2.png) [@jsorlie](https://forum.inductiveautomation.com/u/jsorlie)\
**Post date:** [April 16, 2023, 9:56pm UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/10 "2023-04-16T21:56:33Z")

</div>

FWIW I notice that ordering is lost when using [toDict()](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.1/com/inductiveautomation/ignition/common/script/adapters/PyDocumentObjectAdapter.html#toDict()) method on JSON stored in a [PyDocumentObjectAdapter](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.1/com/inductiveautomation/ignition/common/script/adapters/PyDocumentObjectAdapter.html) (eg. in a [Document](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.1/com/inductiveautomation/ignition/common/document/Document.html) memory tag in a UDT) to get a [dictionary](https://docs.inductiveautomation.com/display/DOC81/Dictionaries). You can however get the original JSON ordering using the [keys()](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.1/com/inductiveautomation/ignition/common/script/adapters/PyDocumentObjectAdapter.html#keys()) method prior to converting the JSON object to a dictionary with [toDict()](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.1/com/inductiveautomation/ignition/common/script/adapters/PyDocumentObjectAdapter.html#toDict()).

---

<div class="post-metadata">

**Author:** ![eMax](https://avatars.discourse-cdn.com/v4/letter/e/cdc98d/32.png) [@eMax](https://forum.inductiveautomation.com/u/eMax)\
**Post date:** [October 6, 2023, 5:09pm UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/11 "2023-10-06T17:09:20Z")

</div>

Hi there.  
I'm sorry, I know this is a bit old post, but I have a problem on this topic and I didn't want to open another post on the same topic  
I've searched everywhere on the web, I can't find an example of how to configure the columns, as you answered,

"The `columns` configuration is the answer here"

do you have any suggestions?  
thaks in advance.

---

<div class="post-metadata">

**Author:** ![jlandwerlen](https://avatars.discourse-cdn.com/v4/letter/j/bc8723/32.png) [@jlandwerlen](https://forum.inductiveautomation.com/u/jlandwerlen)\
**Post date:** [October 6, 2023, 5:12pm UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/12 "2023-10-06T17:12:53Z")

</div>

They were referring to the columns configuration in the table.

[https://docs.inductiveautomation.com/display/DOC81/Perspective+-+Table#PerspectiveTable-Properties](https://docs.inductiveautomation.com/display/DOC81/Perspective+-+Table#PerspectiveTable-Properties)

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [October 7, 2023, 8:02am UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/13 "2023-10-07T08:02:25Z")

</div>

What's the issue exactly ?

---

<div class="post-metadata">

**Author:** ![eMax](https://avatars.discourse-cdn.com/v4/letter/e/cdc98d/32.png) [@eMax](https://forum.inductiveautomation.com/u/eMax)\
**Post date:** [October 7, 2023, 8:41am UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/14 "2023-10-07T08:41:12Z")

</div>

Hey, ciao Pascal,  
I'm sorry to bother you againg.  
My problem isn't that big of a deal.  
This code exports the records directly from the namedQuery (if they are not filtered), otherwise I only export the filtered records.  
IF I don't have a filter applied the columns exported to Excel are OK, otherwise IF I have a filter the columns are exported in a different order. So far I've tried with "OrderedDict" but I can't sort them and I was almost thinking of leaving it as it is before you wrote to me.

```auto
def runAction(self, event):
	if self.getSibling("tblDeodorazione").props.filter.results.data:		
		def jsonToDataset(list):
			columns = dict(list[0]).keys()
			data = []
			for item in list:
				row = []
				for column in columns:
					cellValue = item.get(column, '')
					try:
						dict(cellValue)
						cellValue = cellValue['value']
					except:
						pass
					row.append(cellValue)
				data.append(row)
				
			return system.dataset.toDataSet(columns, data)
				
		json = self.getSibling("tblDeodorazione").props.filter.results.data
		data = jsonToDataset(json)
		Excel_xlsx = system.dataset.toExcel(True,[data])
		system.perspective.download("rptDeodorazione" + "(" + self.getSibling("tblDeodorazione").props.filter.text + ")" + ".xlsx",Excel_xlsx)
	else:
		parameters = {"parStartDate":self.getSibling("startDate").props.value, "parEndDate":self.getSibling("endDate").props.value}
		data = system.db.runNamedQuery("UGP9/qryDeodorazione", parameters)	
		data = system.dataset.toExcel(True, [data])
		system.perspective.download("rptDeodorazione.xlsx",data)

```

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [October 7, 2023, 8:58am UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/15 "2023-10-07T08:58:56Z")

</div>

There are a few things to fix there, I'll need some time top go over the code in more details.

Alright so first things first:

- don't call things `list`. That's a python built-in.
- you should define `jsonToDataset` in your project's library, not here.

Now if I understand correctly, your issue is that you lose the column order when using filtered data.  
I'm not sure if this is the result of the `jsonToDataset` function or if it's already unordered before, but I believe the simplest solution might be to pass a list with the expected columns, in the expected order. You can get this from the table's `columns` property:

```python
columns = [col.field for col in columns]

```

Then you only need to use this list to order your columns, either when you build the dataset, or afterward with (I believe) `system.dataset.filterColumns`.

I'm not rewriting the `jsonToDataset` function just yet, because I'm not sure about why the `try` is there for, but simply removing its first line and adding a `columns` parameter to pass the columns list as an argument should fix the issue.

---

<div class="post-metadata">

**Author:** ![eMax](https://avatars.discourse-cdn.com/v4/letter/e/cdc98d/32.png) [@eMax](https://forum.inductiveautomation.com/u/eMax)\
**Post date:** [October 7, 2023, 10:03am UTC](https://forum.inductiveautomation.com/t/dictionary-key-order/63799/16 "2023-10-07T10:03:33Z")

</div>

Wow, you're great!  
I just replaced:

```auto
columns = dict(list[0]).keys()

```

with your suggestion:

```auto
columns = [col.field for col in self.getSibling("tblDeodorazione").props.columns]

```

and Voilà everything is perfect.

Merci beaucoup.
