# Help Sorting Dictionary

**URL:** <https://forum.inductiveautomation.com/t/help-sorting-dictionary/78970>\
**Category:** General Discussion\
**Tags:** perspective, ignition81, scripting\
**Created:** [September 11, 2023, 5:44pm UTC](https://forum.inductiveautomation.com/t/help-sorting-dictionary/78970 "2023-09-11T17:44:11Z")\
**Posts on this page:** 10\
**Page:** 1

<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:** [September 11, 2023, 5:44pm UTC](https://forum.inductiveautomation.com/t/help-sorting-dictionary/78970/1 "2023-09-11T17:44:11Z")

</div>

I am being present data as such:

```auto
{
	u'Key1': 
		[
		{'parent': True, 'label': u'myLabel1', 'status': ''}, 
		{'parent': True, 'label': u'myLabel2', 'status': ''}
		], 
	'Key2': 
		[
		{'parent': False, 'label': u'myLabel1', 'status': ''}, 
		{'parent': False, 'label': u'myLabel2', 'status': ''}
		]
}

```

Hoping for a little advice from the Python gurus. First, is this considered a dictionary of list of dictionaries? If not, what is the correct terminology?

Second, I would like to sort the data in two ways. One, the keys (currently Key1/2 sorted based on `parent`, it should always be first. Then, then the list of dictionaries under each of these keys sort based on `label`, alphabetical.

What is the pythonish way to accomplish this.

Is using `sorted()` an option?

---

<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 11, 2023, 6:04pm UTC](https://forum.inductiveautomation.com/t/help-sorting-dictionary/78970/2 "2023-09-11T18:04:32Z")

</div>

Jython dictionaries (and most java dictionaries) are unsortable. That is, they "sort" by the hash function used for accelerated lookup. On top of that, if you assign an actual ordered/sorted dictionary to a Perspective property, it will be remapped into an unordered dictionary. ☹

So, how do you intend to **use** this?

FWIW, as long as you don't assign to Perspective, you can use instances of [ConcurrentSkipListMap](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ConcurrentSkipListMap.html) in place of your dictionaries and they will **stay** sorted.

---

<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:** [September 11, 2023, 6:21pm UTC](https://forum.inductiveautomation.com/t/help-sorting-dictionary/78970/3 "2023-09-11T18:21:49Z")

</div>

I was going to "shove" this into a flex repeater. So I guess this is an example of the XY question.

I have faceplates for specific devices like valves, motors, etc. I like to show an alarm list on the faceplates, this is easy enough. But, there are times where multiple devices are "grouped" together, so I want to show alarms for all that belong to each other. This is easy enough.

The issue for me is I don't want all alarms to be listed together, I want them grouped by type. I kind of have that working except for sorting. I can get the alarms to sort alphabetical, but the groups I can't.

Here is what I am after (minus Main should be first),

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

Here is my mess of code so far that I'm playing with (be gentle 🙂 ):

```auto
from com.inductiveautomation.ignition.common.alarming.config import CommonAlarmProperties
from com.inductiveautomation.ignition.common import QualifiedPathUtils
from collections import defaultdict

if tagPath:

	source = "*" + shared.tags.general.tagPath(tagPath) + "*"
	state = ["Active, Unacknowledged", "Active, Acknowledged", "Cleared, Unacknowledged"]
	alarms = system.alarm.queryStatus(source=source)
	
	alarmDict = defaultdict(list) #Used to create a dictionary of dictionaries, to separate alarms by UDT
	for alarm in alarms:
		
		#Create a useful key, also used as a header for the flex repeater instances
		tag = shared.tags.general.tagParent(QualifiedPathUtils.toTagPathNew(alarm.getSource()).toStringFull(), tp=True)
		meta = system.tag.readBlocking(tag + ".Documentation")[0].value
		key = meta + " - " + tag.rsplit("/")[-1] if meta else tag.rsplit("/")[-1]
		
		#Read IsParent, this should display first and use the heading label "Main"
		parent = system.tag.readBlocking(tag + "/Cfg_IsParent")[0].value
	
		alarmData = {
			'hasAlarmPath': tag + "/Cfg_Has" + alarm.name.split("_")[-1] + "Alm",
			'label': alarm.name, 
			'status': alarm.state if str(alarm.state) in state else "",
			'parent': parent
		}
		if alarmData not in alarmDict[key if not parent else "Main"]:
			alarmDict[key if not parent else "Main"].append(alarmData)
	
	alarms = []
	for alarm in alarmDict:
		alarmData = {
			"alarms": sorted(alarmDict[alarm], key = lambda d: d['label'].lower()), #Sort alphabetically case insensitive
			"device": alarm if len(alarmDict) > 1 else "" #If empty then we hide
		}
		alarms.append(alarmData)

	return alarms

```

---

<div class="post-metadata">

**Author:** ![ryan.white](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ryan.white/32/73193_2.png) [@ryan.white](https://forum.inductiveautomation.com/u/ryan.white)\
**Post date:** [September 11, 2023, 6:54pm UTC](https://forum.inductiveautomation.com/t/help-sorting-dictionary/78970/4 "2023-09-11T18:54:42Z")

</div>

Fast dirty way to adjust your current code to sort:  
Add `import operator` to the top of your code  
After your for loop that adds the items to `alarms` put:

```auto
alarms.sort(key=operator.itemgetter('device'))

```

That will run through your alarms list and sort by the item key 'device'. That will get you working 'for now'™

Some side notes:

- You are making multiple single tag calls to `system.tag.readBlocking`, It's more efficient to do a single call with multiple tag paths.

- You first define `alarms` as the result from a call to `system.alarm.queryStatus`, but then later define it as a list that you are putting data into. Avoid reusing the same variable name in the same function, instead choose different variable names that can still clearly articulate what data it holds. In this case the second `alarms` could be something like `repeaterAlarmList` or similar (I suck with variable names too)

---

<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:** [September 11, 2023, 7:01pm UTC](https://forum.inductiveautomation.com/t/help-sorting-dictionary/78970/5 "2023-09-11T19:01:35Z")

</div>

Thanks Ryan. this is a work in progress. I'm aware of the reads and variable names.  
I'm usually very lazy with names and reads in the beginning. I typically go back through and cleanup.

Just a bad habit of mine.

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [September 11, 2023, 7:04pm UTC](https://forum.inductiveautomation.com/t/help-sorting-dictionary/78970/6 "2023-09-11T19:04:49Z")

</div>

> [@jlandwerlen](#):
>
> I'm usually very lazy with names and reads in the beginning. I typically go back through and cleanup.
> 
> Just a bad habit of mine.

Nah, make it work, then make it pretty is as good an approach as any as long as it doesn't make it into production code.

---

<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:** [September 11, 2023, 7:40pm UTC](https://forum.inductiveautomation.com/t/help-sorting-dictionary/78970/7 "2023-09-11T19:40:55Z")

</div>

Getting this

```auto
Traceback (most recent call last):
  File "<input>", line 41, in <module>
TypeError: an integer is required

```

Line 41 is this

```auto
print alarms.sort(operator.itemgetter('device'))

```

I added the import and replaced the return with print (testing from script console), using the code snippet supplied. Any ideas?

---

<div class="post-metadata">

**Author:** ![ryan.white](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ryan.white/32/73193_2.png) [@ryan.white](https://forum.inductiveautomation.com/u/ryan.white)\
**Post date:** [September 11, 2023, 8:36pm UTC](https://forum.inductiveautomation.com/t/help-sorting-dictionary/78970/8 "2023-09-11T20:36:50Z")

</div>

Ah typo on my part, it should be `alarms.sort(key=operator.itemgetter('device'))`, I've corrected original.

---

<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:** [September 11, 2023, 9:18pm UTC](https://forum.inductiveautomation.com/t/help-sorting-dictionary/78970/9 "2023-09-11T21:18:14Z")

</div>

Thanks. I still wasn't able to get what you copied to work. This did though,

```auto
sorted(alarms, key=operator.itemgetter('device'))

```

---

<div class="post-metadata">

**Author:** ![ryan.white](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ryan.white/32/73193_2.png) [@ryan.white](https://forum.inductiveautomation.com/u/ryan.white)\
**Post date:** [September 11, 2023, 9:26pm UTC](https://forum.inductiveautomation.com/t/help-sorting-dictionary/78970/10 "2023-09-11T21:26:49Z")

</div>

Strange that it doesn't let you do `.sort` but yeah, sorted will return the sorted list so they more or less do the same thing.

I checked the code that I was referencing and I'm calling .sort on a list with no issues, so maybe a typecasting thing?
