# Python List Comprehensions Help

**URL:** <https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621>\
**Category:** Ignition\
**Created:** [February 28, 2022, 3:12pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621 "2022-02-28T15:12:54Z")\
**Posts on this page:** 20\
**Page:** 3

<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:** [March 10, 2022, 5:26pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/41 "2022-03-10T17:26:24Z")

</div>

I fail to see the issue…  
Do you mean you want to do something like this ?

```python
paths = (
	[baseTag.format(i, i, i, counterS) for i in exceptions]
	+ [baseTag.format(i, i, i, counterA) for i in nonExceptions]
)

```

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [March 10, 2022, 5:51pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/42 "2022-03-10T17:51:28Z")

</div>

I think you were reading about nested for loops in one comprehension. Both expanded and comprehension forms in this example:

```python
numMachines = 18
exceptions =[2,4,5,8,9,10,11,12]
nonExceptions = [3,6,14,15,16,17,18]
counters = ['NetSCounter', 'NetACounter'] 
baseNetTags ='[Test]M{machineNum:02d}/M{machineNum:02d}ProductionData/M{machineNum:02d}/{counter}'

pathsNewNet = pathsNewNet=[baseNetTags.format(machineNum=i,counter=k) for i in xrange(1,numMachines + 1) for k in counters]

print 'Comprehension:'
print pathsNewNet

expandedLoopTags = []
for i in xrange(1,numMachines + 1):
	for k in counters:
		expandedLoopTags.append(baseNetTags.format(machineNum=i,counter=k))

print '----------------'
print 'Expanded Loop:'
print expandedLoopTags

```

---

<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:** [March 10, 2022, 5:55pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/43 "2022-03-10T17:55:03Z")

</div>

> [@zacharyw.larson](#):
>
> I can still use system.tag.read, so what is happening when I use it?  
> I didn’t understand the part about here:  
> [7.9 to 8.1 Upgrade Guide - Ignition User Manual 8.1 - Ignition Documentation](https://docs.inductiveautomation.com/display/DOC81/7.9+to+8.1+Upgrade+Guide)

I think I can help clarify this a little, although, this is just my outsider understanding of the issue and why I think the change was a good one.

In 7.9 there were 6 functions that worked with the tag system

1. system.tag.read()
2. system.tag.readAll()
3. system.tag.write()
4. system.tag.writeAll()
5. system.tag.writeSyncronous()
6. system.tag.writeAllSyncronous()

This was confusing for some users who expected similarly named functions to behave the same. For instance, `system.tag.write()` is an \*asynchronous \* function, meaning that it does not block the thread on which it is called. However, `system.tag.read()` is a _synchronous_ function, meaning that it does block the thread on which it is called.

If you wanted a write operation to block the thread, then you needed to explicitly call `system.tag.writeSyncronous()`.

There was no direct function for an asynchronous read and if you wanted to do that then you had to do it explicitly.

I think you can see how this could be confusing. In then end asynchronous or not, all of the functions eventually did one of two operations, `readBlocking` or `writeBlocking`, just sometimes that was wrapped inside of another function which made the operation asynchronous or not.

In order to clear up some of the potential confusion they removed the abstraction that was in place where it could be.

So we arrived at the now 4 functions with a clear meaning from just the naming convention.

1. system.tag.readBlocking()
2. system.tag.readAsync()
3. system.tag.writeBlocking()
4. system.tag.writeAsync()

Now when you call these functions you know what you get just from the name. `readBlocking` will block the thread, `readAsync` will not block the thread.

I don't know if there were any changes under the hood, but even so I feel the name change was a great move.

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 10, 2022, 6:13pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/44 "2022-03-10T18:13:00Z")

</div>

I call a script at 6:58am to sum net and gross quantities.  
Do you recommend to use :  
system.tag.readAsync()  
and  
system.tag.writeAsync()

?

and scenario 2  
I have read a ton of things, do math, write to a ton of things  
then it is recommended to use as few of blocking as I can?

I am researching when to use asych programming, but I am having a hard time with the abstractness/subjectiveness

---

<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:** [March 10, 2022, 7:19pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/45 "2022-03-10T19:19:32Z")

</div>

> [@zacharyw.larson](#):
>
> Do you recommend to use :  
> system.tag.readAsync()  
> and  
> system.tag.writeAsync()

What you use depends on what you need to happen in the script.

1. Is the script you're writing dependent upon the values of the tags you're reading?
2. If so, would waiting on the tags to be read, lock up a thread that a user is interacting with?

Off the top of my head, I would say the majority of the time you don't need anything other than `readBlocking()` and `writeBlocking()` the other functions are there for the times when you do need that special functionality.

I missed some other, probably important infomration in my last post. The biggest change, was the removal of the `readAll()`, `writeAll()` wrappers. Now the functions all take a list of tagPaths, and values if writing, removing the need for a `readAllBlocking()`.

> [@zacharyw.larson](#):
>
> and scenario 2  
> I have read a ton of things, do math, write to a ton of things  
> then it is recommended to use as few of blocking as I can?

**Always** minimize the number of times you block a thread.

Scripts which I write that utilize the tag system always follow this pattern:

1. read all tags which will be used in the script
2. do the work
3. write out all of the tags which need to be written.

Don't use 5 calls to `readBlocking` when you can use just one.

On the other hand don't go looking for optimizations just to look for optimizations. For instance look at this code snipit

```python
from java.lang import System

values = range(1,100000)
test1Total = 0
test2Total = 0
test3Total = 0
for i in range(10):
	start = System.nanoTime()
	netTotal = sum([i for i in values if i % 2])
	end = System.nanoTime()
	
	test1Total += end - start
	
	start = System.nanoTime()
	netTotal = sum(i for i in values if i % 2)
	end = System.nanoTime()
	
	test2Total += end - start
	
	start = System.nanoTime()
	
	evenValues = []
	for i in values:
		if i % 2:
			evenValues.append(i)
	netTotal = sum(evenValues)
	end = System.nanoTime()
	
	test3Total += end - start
		
print 'Test 1 took an average of {} ms'.format(test1Total/10000000)
print 'Test 2 took an average of {} ms'.format(test2Total/10000000)
print 'Test 3 took an average of {} ms'.format(test3Total/10000000)

```

I ran this 10 times on my system, here is the output:

```auto
>>> 
Test 1 took an average of 14 ms
Test 2 took an average of 5 ms
Test 3 took an average of 15 ms
>>> 
Test 1 took an average of 24 ms
Test 2 took an average of 4 ms
Test 3 took an average of 27 ms
>>> 
Test 1 took an average of 14 ms
Test 2 took an average of 4 ms
Test 3 took an average of 15 ms
>>> 
Test 1 took an average of 24 ms
Test 2 took an average of 4 ms
Test 3 took an average of 26 ms
>>> 
Test 1 took an average of 24 ms
Test 2 took an average of 4 ms
Test 3 took an average of 28 ms
>>> 
Test 1 took an average of 24 ms
Test 2 took an average of 4 ms
Test 3 took an average of 26 ms
>>> 
Test 1 took an average of 24 ms
Test 2 took an average of 4 ms
Test 3 took an average of 26 ms
>>> 
Test 1 took an average of 23 ms
Test 2 took an average of 5 ms
Test 3 took an average of 26 ms
>>> 
Test 1 took an average of 14 ms
Test 2 took an average of 5 ms
Test 3 took an average of 15 ms
>>> 
Test 1 took an average of 14 ms
Test 2 took an average of 5 ms
Test 3 took an average of 15 ms
>>> 

```

All three tests have the exact same end result, and it's clear which code executes the quickest, however, when you're trouble shooting an issue are you generally looking for a code change which gives you a 10-20 ms boost? No, you're usually looking for more.

I'm not saying not to worry about performance, I'm saying you have to balance what it's worth spending your time on.

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [March 10, 2022, 7:31pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/46 "2022-03-10T19:31:38Z")

</div>

> The real problem is that **programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times** ; premature optimization is the root of all evil (or at least most of it) in programming.

Good advice. The only times I would say its not true is if the optimization is obvious and easy (ie indexing a db table on a column you know will be used a lot) or if the optimization happens to also align with good design/coding (in this case, using one call to readBlocking instead of 5 - this will make the code simpler and more easily maintainable).

Beyond these two things, its hard to tell what will be a bottleneck that requires optimization prior to it happening.

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 10, 2022, 7:44pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/47 "2022-03-10T19:44:21Z")

</div>

I ran the test on a subsection of my code and I got 2ms with a bunch of read calls then 0ms with the single read call.

I thought the way the script ran before had caused a crash though.  
At the time of running the script, I saw a crash on the gateway.

I don’t know how why the timing of the script would be the same as the crash though if the time was only like 20ms at worst case.

I am a little concerned I revised the script and didn’t really get as much benefit as hoped.

* * *

At least my code is now more robust though as even if the tags are not reading correctly the code will run.

ah, I can’t tell if that helps either. Before the script would error out. Then we wouldn’t have any numbers totaled. Now if a tag is bad, we get all the numbers except for the machine that had bad numbers. So we might miss this now.

---

<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:** [March 11, 2022, 10:33am UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/48 "2022-03-11T10:33:54Z")

</div>

If you’re worried about missing information about bad tag quality, you can be more specific about how you handle quality.

for example, if you want to filter out tags that don’t exist, but retain tags that do exist but returned a bad quality (note that I don’t have ignition on this computer, so I can’t test if everything works, but I hope you’ll get the point):

```python
tags = [
	{
		'path': path,
		'qval': tag
	} for path, tag in zip(paths, system.tag.readBlocking(paths)) if tag.quality.code == 519
]

total = sum(tag['qval'].value for tag in tags if tag['qval'].quality.isGood())
bad_tags = [tag['path'] for tag in tags if tag['qval'].quality.isNotGood()]

```

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 11, 2022, 2:43pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/49 "2022-03-11T14:43:43Z")

</div>

I really appreciating seeing how to do multiple lists.

**update, figured this out.  
I don’t know how to strikeout, but now sorting makes sense.  
The two list example did not order them 1-17.  
It had one set, then the next.**

```auto
How is the sorting working?
Once with two lists, the suffix was ignored, and the results were sorted 1-17

```

Once with four lists, the suffix order was maintained and results were sorted 1-17 of each in order gross, net, sticks, standard volumes

I am happy with the sorting both last time and this time.  
I want to know how it worked in both cases though. I expected one of them to be in a different order.

For different counters on the end of paths, they were in the correct order 1-17 with different suffixes.

```auto
paths = (	[baseTag.format(i, i, i, counterS) for i in exceptions]+
            [baseTag.format(i, i, i, counterA) for i in nonExceptions])

```

Results were in sequence from 1-17 each with their unique suffix counter in the path

In this example, my paths came out in the order that they were put in.  
1-17 gross  
1-17 net  
1-17 sticks  
1-17 standard volumes  
If it were just ascii, then I think Standard would be before Sticks.

I used this to check them all.  
Below is a snip of some of the results.

```auto
numMachines=18
baseGrossPaths='[Test]here/M{0:02d}/Combined Shifts/Gross'
#then the next three base paths

paths = ([baseGrossPaths.format(i) for i in xrange(1,numMachines + 1) if i not in exclusions]+
		 [baseNetPaths.format(i) for i in xrange(1,numMachines + 1) if i not in exclusions]+
		 [baseSticksPaths.format(i) for i in xrange(1,numMachines + 1) if i not in exclusions]+
		 [baseStandardVolumePaths.format(i) for i in xrange(1,numMachines + 1) if i not in exclusions])
paths[0]
paths[1]
paths[2]
paths[3]
paths[4]
paths[5]
paths[6]
paths[7]
paths[8]
paths[9]
paths[10]
paths[11]
paths[12]
paths[13]
paths[14]
paths[15]
paths[16]
paths[17]
paths[18]
paths[19]
paths[20]
paths[21]
paths[22]
paths[23]
paths[24]
paths[25]
paths[26]
paths[27]
paths[28]
paths[29]
paths[30]
paths[31]
paths[32]
paths[33]
paths[34]
paths[35]
paths[36]
paths[37]
paths[38]
paths[39]
paths[40]
paths[41]
paths[42]
paths[43]
paths[44]
paths[45]
paths[46]
paths[47]
paths[48]
paths[49]
paths[50]
paths[51]
paths[52]
paths[53]
paths[54]
paths[55]
paths[56]
paths[57]
paths[58]
paths[59]
paths[60]
paths[61]
paths[62]
paths[63]
paths[64]
paths[65]
paths[66]
paths[67]

Values17by4Spaces = [0]*17*4
Values17by4Spaces

```

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

---

<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:** [March 11, 2022, 3:34pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/50 "2022-03-11T15:34:13Z")

</div>

First… may i suggest not copying 67 lines of print ? 😃

```python
print '\n'.join(paths)

```

Lists keep their order, dicts don’t. If you end up with two different ordering in lists, then you didn’t put the elements in in the same order.

---

<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:** [March 11, 2022, 4:03pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/51 "2022-03-11T16:03:04Z")

</div>

> [@zacharyw.larson](#):
>
> I don’t know how to strikeout

Surround the text with html-ish \<s\>...\</s\>.  
This in the comment editor:

```auto
<s>This is a strikeout test.</s> This is normal.

```

Becomes this:

> [@](#):
>
> ~~This is a strikeout test.~~ This is normal.

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 11, 2022, 4:27pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/52 "2022-03-11T16:27:21Z")

</div>

thanks very much for the  
`print '\n'.join(paths)`  
That will save me some excel time for sure.

I got this list while testing and trying to do the next thing

```auto
notGoodTags =[p for p in system.tag.readBlocking(paths) if 'Good' not in str(p.quality)]

```

It didn’t tell me which machines had the bad tags though.

* * *

I am working on a situation like this right now:

```auto
17 variables = 17 reads
if statement
    17 writes of the 17 variables

```

I think my solution is like:  
read the good values to a list  
append a list of i values that were good  
generate the writing paths based on the good i values  
check if the lists match  
write from one list to the other

trying this, but it gives me the tags, and I want to get the numbers

```auto
numMachines = 18
exceptions =[2,4,5,8,9,10,11,12]
nonExceptions = [3,6,14,15,16,17,18]

baseTag ='[Test]M{0:02d}/M{0:02d}ProductionData/M{0:02d}{counter}'

paths = ([baseTag.format(i, i, i, counter='S') for i in exceptions] +
         [baseTag.format(i, i, i, counter='A') for i in nonExceptions])
goodTagsForSticks =[i for in system.tag.readBlocking(paths) if i.quality.good]

```

I think could do this with Jordan’s demonstration above several posts.  
I was trying to do it within a list comprehension nested for loop, but maybe that is not the way.

Update:

```auto
goodSticksTagsMachines =[p for p in system.tag.readBlocking(paths)]
goodSticksTagsMachines

goodtags= [k for k in exceptions if 'Good' not in goodSticksTagsMachines]
goodtags

```

~~I got it~~  
this did not work

---

<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:** [March 11, 2022, 4:52pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/53 "2022-03-11T16:52:00Z")

</div>

I’m not quite sure what you’re trying to do… But a few things:

```python
baseTag ='[Test]M{0:02d}/M{0:02d}ProductionData/M{0:02d}{counter}'
baseTag.format(i, i, i, counter='S')

```

You don’t need to repeat the `i` here. you’re using `{0:02d}` which means ‘use the first argument’, so they’re all using the first `i` you’re passing. Which I expect is the reason you named the `{counter}` one.

```python
baseTag ='[Test]M{0:02d}/M{0:02d}ProductionData/M{0:02d}{1}'
baseTag.format(i, 'S')

```

will do the same thing.

```python
goodSticksTagsMachines = [p for p in system.tag.readBlocking(paths)]

```

You don’t need a list comprehension here. What this does is take each element in the list, then make another list with them.

```python
goodTagsForSticks = [i for in system.tag.readBlocking(paths) if i.quality.good]

```

This will only filter out the tags that have a bad quality. You need to get the value from them if you want the numbers:

```python
goodTagsForSticks = [tag.value for tag in system.tag.readBlocking(paths) if tag.quality.good]

```

I encourage you to use more descriptive names for your variables, it might help you catch logical flaws like this one

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 11, 2022, 5:10pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/54 "2022-03-11T17:10:16Z")

</div>

Thanks again Pascal

* * *

regarding:  
`goodTagsForSticks = [tag.value for tag in system.tag.readBlocking(paths) if tag.quality.good]`  
Is there a good method to get which machine numbers have bad tags from within a single list comprehension, or is it best to make lists and run the check, then append?

I am switching to designating tag when I want the tag, thanks for the recommendation.  
In this case though, I really wanted to know the number of the machine, and didn’t figure out how to get it without making a list, checking against it, and appending/writing a new list.

* * *

I am reading 17 machine values to write 17 value snapshots  
Right now the script:

```auto
17 variables = 17 reads
if statement 
    17 writes of the 17 variables that were read

```

my solution

```auto
numMachines = 18
exceptions =[2,4,5,7,8,9,10,11,12]
nonExceptions = [3,6,14,15,16,17,18]

baseTag ='[Test]M{0:02d}/M{0:02d}ProductionData/M{0:02d}{counter}'

pathsStickValues = ([baseTag.format(i,counter='S') for i in exceptions] +
                    [baseTag.format(i,counter='A') for i in nonExceptions])

valuesSticks= [i.value for i in system.tag.readBlocking(pathsStickValues)]

baseSticksSnapshots ='[Test]M{0:02d}/M{0:02d}ProductionData/Sticks Snapshot'
pathsSticksSnapshots=([baseSticksSnapshots.format(i) for i in exceptions]+
	                  [baseSticksSnapshots.format(i) for i in nonExceptions])

print '\n'.join(pathsSticksSnapshots)
#system.tag.writeblocking(pathsSticksSnapshots,valueSticks)  

```

updated

```auto
valuesSticks= [i.value for i in system.tag.readBlocking(pathsStickValues)]
was
valuesSticks= [i.value for i in system.tag.readBlocking(paths)]

```

---

<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:** [March 11, 2022, 6:03pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/55 "2022-03-11T18:03:30Z")

</div>

I still have no idea what you’re trying to do 😃  
What are ‘sticks’ ? What are ‘snapshots’ ?

```python
pathsSticksSnapshots=([baseSticksSnapshots.format(i) for i in exceptions]+
	                  [baseSticksSnapshots.format(i) for i in nonExceptions])
# could do this instead:
pathsSticksSnapshots = [baseSticksSnapshots.format(i) for i in exceptions + nonExceptions]

```

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 11, 2022, 6:14pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/56 "2022-03-11T18:14:54Z")

</div>

sticks/pieces/products

just a name for products in this case

snapshots, well that is a name that some people used to describe a scenario where they wanted put a value that was changing and kind of capture how it was at a certain time like a freezeframe/snapshot is a still picture of life.

probably has to be a really odd thing to explain if English isn’t a native language

It combines idioms and words that formerly were used more frequently.

We end up making new meanings for words that aren’t very common.

Then later, words will be even more confusing because they will have so many more meanings. haha

* * *

unless you meant more generally what am I doing?

I am learning a ton and revising some scripts that were causing issues on my gateway so I can add a couple more machines we need and smooth performance both.

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [March 11, 2022, 7:07pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/57 "2022-03-11T19:07:18Z")

</div>

Personally, I’d likely use a dictionary to store lookup information. In your case, it’s just one thing to look up, a counter type; however, you can easily add other lookup information as needed.

```python
# Lookup dictionary. Note the ones that are commented out.
machineDict = {
               #1 : {'counterType' : None},
               2 : {'counterType' : 'S'},
               3 : {'counterType' : 'A'},
               4 : {'counterType' : 'S'},
               5 : {'counterType' : 'S'},
               6 : {'counterType' : 'A'},
               7 : {'counterType' : 'S'},
               8 : {'counterType' : 'S'},
               9 : {'counterType' : 'S'},
               10 : {'counterType' : 'S'},
               11 : {'counterType' : 'S'},
               12 : {'counterType' : 'S'},
               #13 : {'counterType' : None},
               14 : {'counterType' : 'A'},
               15 : {'counterType' : 'A'},
               16 : {'counterType' : 'A'},
               17 : {'counterType' : 'A'},
               18 : {'counterType' : 'A'}
              }

baseTag = '[Test]M{0:02d}/M{0:02d}ProductionData/M{0:02d}{1}'
baseSticksSnapshots = '[Test]M{0:02d}/M{0:02d}ProductionData/Sticks Snapshot'

# You can create your input and output tag lists in one iteration. 
# Just because you can use a comprehension doesn't always mean that you should. ;)
pathsStickValues, pathsSticksSnapshots = [], []
for i in machineDict.keys():
	pathsStickValues.append = baseTag.format(i, machineDict[i]['counterType'])
	pathsSticksSnapshots.append = baseSticksSnapshots.format(i)
	
valuesSticks = [i.value for i in system.tag.readBlocking(paths)]

```

* * *

An example of a more complex lookup dictionary, just to illustrate. This particular one is used to parse a bill of materials into something more useful for the assembly line.

```python
bomLookupDict = {
                 'dcm' : {'desc' : ['DCM']},
                 'psat' : {'desc' : ['Pressure']},
                 'harness' : {'desc' : ['Harness']},
                 'latch' : {'desc' : ['Latch']},
                 'speaker' : {'desc' : ['Speaker']},
                 'antenna' : {'desc' : ['Antenna']},
                 'module' : {'desc' : [
                                                 'Assem Frt',
                                                 'Asm Frt',
                                                 'AssemFrt',
                                                 'AsemFrtSht',
                                                 'AssemFrtSht'
                                                ],
                                 '68223827AI' : {'type' : 'long', 
                                                 'drive' : 'manual',
                                                 'handle' : 'BLACK',
                                                 'lock_knob' : 'BLACK'
                                                 },
                                 '68429127AI' : {'type' : 'long',
                                                 'drive' : 'manual',
                                                 'handle' : 'BLACK',
                                                 'lock_knob' : 'BLACK'
                                                 },
                                 '68429135AD' : {'type' : 'long',
                                                 'drive' : 'manual',
                                                 'handle' : 'BLACK',
                                                 'lock_knob' : 'BLACK'
                                                },
                                 '68501197AA' : {'type' : 'long',
                                                 'drive' : 'power',
                                                 'handle' : 'BLACK',
                                                 'lock_knob' : 'BLACK'
                                                },
                                 '68429077AA' : {'type' : 'long',
                                                 'drive' : 'power',
                                                 'handle' : 'SZ0',
                                                 'lock_knob' : 'BLACK'
                                                },
                                 '68429075AA' : {'type' : 'long',
                                                 'drive' : 'power',
                                                 'handle' : 'SZ0',
                                                 'lock_knob' : 'SZ6'
                                                },
                                 '68429081AA' : {'type' : 'long',
                                                                'drive' : 'power',
                                                                'handle' : 'SZ6',
                                                                'lock_knob' : 'SZ6'
                                                               },
                                 '68568935AA' : {'type' : 'long',
                                                               'drive' : 'manual',
                                                               'handle' : 'BLACK',
                                                               'lock_knob' : 'BLACK'
                                                               },
                                 '68568939AA' : {'type' : 'long',
                                                               'drive' : 'power',
                                                               'handle' : 'BLACK',
                                                               'lock_knob' : 'BLACK'
                                                               },
                                 '68568945AA' : {'type' : 'long',
                                                               'drive' : 'power',
                                                               'handle' : 'SZ6',
                                                               'lock_knob' : 'SZ6'
                                                               },
                                 '68429087AA' : {'type' : 'short',
                                                 'drive' : 'power',
                                                 'handle' : 'BLACK',
                                                 'lock_knob' : 'BLACK'
                                                },
                                 '68429091AA' : {'type' : 'short',
                                                 'drive' : 'power',
                                                 'handle' : 'SZ6',
                                                 'lock_knob' : 'SZ6'
                                                },
                                 '68429099AA' : {'type' : 'short',
                                                 'drive' : 'power',
                                                 'handle' : 'SZ0',
                                                 'lock_knob' : 'SZ0'
                                                },
                                 '68429093AA' : {'type' : 'short',
                                                 'drive' : 'power',
                                                 'handle' : 'TZ3',
                                                 'lock_knob' : 'SZ6'
                                                },
                                 '68429095AA' : {'type' : 'short',
                                                 'drive' : 'power',
                                                 'handle' : 'TZ6',
                                                 'lock_knob' : 'SZ6'
                                                },
                                 '68429097AA' : {'type' : 'short',
                                                 'drive' : 'power',
                                                 'handle' : 'TZS',
                                                 'lock_knob' : 'SZ6'
                                                },
                                 '68526619AA' : {'type' : 'short',
                                                 'drive' : 'power',
                                                 'handle' : 'SKS',
                                                 'lock_knob' : 'SZ6'
                                                },
                                 '68429089AA' : {'type' : 'short',
                                                 'drive' : 'power',
                                                 'handle' : 'SZ0',
                                                 'lock_knob' : 'BLACK'
                                                },
                                 '68570689AA' : {'type' : 'short',
                                                 'drive' : 'power',
                                                 'handle' : 'BLACK',
                                                 'lock_knob' : 'BLACK'
                                                },
                                 '68570723AA' : {'type' : 'short',
                                                 'drive' : 'power',
                                                 'handle' : 'SZ6',
                                                 'lock_knob' : 'SZ6'
                                                },
                                 '68570735AA' : {'type' : 'short',
                                                 'drive' : 'power',
                                                 'handle' : 'TZ3',
                                                 'lock_knob' : 'SZ6'
                                                },
                                 '68570737AA' : {'type' : 'short',
                                                 'drive' : 'power',
                                                 'handle' : 'TZ6',
                                                 'lock_knob' : 'SZ6'
                                                },
                                 '68570739AA' : {'type' : 'short',
                                                 'drive' : 'power',
                                                 'handle' : 'TZS',
                                                 'lock_knob' : 'SZ6'
                                                },
                                 '68570741AA' : {'type' : 'short',
                                                 'drive' : 'power',
                                                 'handle' : 'SKS',
                                                 'lock_knob' : 'SZ6'
                                                }
                                }
                }

```

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 11, 2022, 7:36pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/58 "2022-03-11T19:36:57Z")

</div>

When I see a dictionary, I think of it as a future relatively unchanging table that will make for using in queries. Or are dictionaries more optimal than queries in that application?  
I only made a few dictionaries and in my application there were superseded by tables and queries.

When using the Ignition reporting, is it more common to use the query table?  
I was thinking if I weren’t adding two machines and smoothing the scripts, that are linked to simple table report components, I would be making the query tables.

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [March 11, 2022, 7:58pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/59 "2022-03-11T19:58:27Z")

</div>

The answer, as with most things, is ‘it depends’. 🙂

In my particular application, the bom info for a production order comes from a file. Since my lookups are defined in a dictionary, I don’t have the round trip to the db. Until model year changes, it’s relatively unchanging.

That said, I also use dictionaries to manipulate datasets. You’ll notice I have a lot of [such posts](https://forum.inductiveautomation.com/t/how-to-query-data-from-two-database-peoplesoft-and-microsoft-sql-into-one-power-table/25974/7) on here.  
Joins on db tables are great and useful and are more efficient if they are in the same data source, but if you need to use datasets from two different sources, you’re hosed.

I find that db people will tend to do more with joins and stored procedures, and programmers will tend to do more through scripting.

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [March 11, 2022, 8:39pm UTC](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621/60 "2022-03-11T20:39:23Z")

</div>

I had an error in my post that I had spotted when I saw that last line of code referencing my code.  
Thanks  
I revised and notated the change there.

* * *

When the script says:  
x= system read  
system write ([“singlepath”],[x])

I have that figured out now.  
I get the paths for both  
make a values list  
write that list to the list of paths with system write blocking

* * *

This time it is different though.

`M1gross = system.tag.read[("[Test]m01/m01Prod/m01gross")`  
16 machines more of these and then several sets of 17 machines for others

then later on in the script they basically are combining totals from each shift by adding the current to the running total:  
`system.tag.writeBlocking(["[Test]thisplace/somestuff/M1 gross"], [sytem.tag.read([Test]thisplace/somestuff/M1 gross") +M1gross.value ])`

my solution isn’t working, I tried a lot of stuff, and the closes so far I got was like this:

```auto

thisList =([i.value+k.value for i in system.tag.readBlocking(pathDailySticks) if i.quality.good for k in system.tag.readBlocking(pathsSticks) if k.quality.good])
valueShiftSticks
valueDailySticks
thisList

```

output

```auto
[8100, 18450, 20007, None, 17342, 29520, 0, 19388, 20910, 0, 0, 0, 0, None, 25077, 0, 16717]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[8100, 18450, 20007, 17342, 29520, 0, 19388, 20910, 0, 0, 0, 0, 25077, 0, 16717, 8100, 18450, 20007, 17342, 29520, 0, and on and on and on

```

these tags are not numbered the same  
one set uses two digits and one set use one digit when below 10…grrr

I think I found the way, and it is what Jordan said to do already.

```auto
for (item1, item2) in zip(list1, list2):
    sum_list.append(item1+item2)

print(sum_list)

```

[Previous page](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621.md?page=2)

[Next page](https://forum.inductiveautomation.com/t/python-list-comprehensions-help/56621.md?page=4)
