# PyDataset to Dictionary

**URL:** <https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968>\
**Category:** Maker\
**Tags:** ignition80, scripting\
**Created:** [September 23, 2020, 5:59am UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968 "2020-09-23T05:59:18Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![jxlim](https://avatars.discourse-cdn.com/v4/letter/j/ce7236/32.png) [@jxlim](https://forum.inductiveautomation.com/u/jxlim)\
**Post date:** [September 23, 2020, 5:59am UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/1 "2020-09-23T05:59:18Z")

</div>

Hi,

I have created a pyDataset, 2R x 2C, I would like to convert it to dictionary then to jsonFormat.  
An example for the pyDataset,  
Header = [Fruit, Cost]  
Row1 = [Apple, 5]  
Row2 =[Pear, 1]

I have found similar topic as reference but I am still unable to manipulate the dataset into dictionary. [http://forum.inductiveautomation.com/t/bug-15901-json-encoding-and-decoding-a-dataset-datatype-property/31617](http://forum.inductiveautomation.com/t/bug-15901-json-encoding-and-decoding-a-dataset-datatype-property/31617)

I have manage to do it manually, with the single code below. **Is there any alternative to execute it if I have x amount of row and column in my dataset?**

NewDict = {“Data1”:{Header[0]:pyData[0][0], Header[1]:pyData[0][1]},“Data2”:{Header[0]:pyData[1][0], Header[1]:pyData[1][1]}}

So the end result will be as follow.  
{  
“Data1”:{  
“Fruit”: “Apple”,  
“Cost”: " 5"  
},  
“Data2”:{  
“Fruit”:“Pear”,  
“Cost”: “1”  
}  
}

Thanks in advance!

---

<div class="post-metadata">

**Author:** ![jxlim](https://avatars.discourse-cdn.com/v4/letter/j/ce7236/32.png) [@jxlim](https://forum.inductiveautomation.com/u/jxlim)\
**Post date:** [September 23, 2020, 8:24am UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/2 "2020-09-23T08:24:08Z")

</div>

I manage to solve the conversion, below is the code:

```auto
MainData = []
i = 0
while i < pyData.getRowCount():
	MainData.append("Data" + str(i))
	i = i + 1
	
NewDict = {}
row = 0
col = 0

for j in MainData:
	NewDict[j] = {}
	for k in Header:	
		NewDict[j][k] = pyData.getValueAt(row, col)
		col = col + 1
	row = row + 1
	col = 0

jsonNewStr = system.util.jsonEncode(NewDict, 5)
print jsonNewStr

```

---

<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 23, 2020, 9:15pm UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/3 "2020-09-23T21:15:05Z")

</div>

Just Fyi to be more succinct, you can also use:  
`for i in range(pyData.getRowCount()):`  
Then you don’t need the i=0 or the i+=1 🙂

---

<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:** [September 24, 2020, 11:23am UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/4 "2020-09-24T11:23:46Z")

</div>

Also, if you use zip you can iterate through multiple objects at once.  
Also-also, list and dictionary comprehensions are useful to learn.

```python
Header = pyData.getColumnNames()

NewDict= {}
for row, i in zip(pyData, range(pyData.getRowCount())):
	NewDict['Data'+str(i)] = {colName:value for colName, value in zip(Header, list(row))}
```

---

<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 24, 2020, 11:33am UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/5 "2020-09-24T11:33:44Z")

</div>

I never thought about using zip like that with a for loop to get eaches of both lists… Interesting!

---

<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 24, 2020, 3:32pm UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/6 "2020-09-24T15:32:53Z")

</div>

I mean, as long as we’re golfing, you can also nest the comprehensions:

```auto
NewDict = {
    'Data %s' % i: {
        colName: value
        for colName, value in zip(pyData.columnNames, list(row))
    }
    for i, row in enumerate(pyData)
}

```

---

<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 24, 2020, 5:44pm UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/7 "2020-09-24T17:44:59Z")

</div>

Now you’re just showing off 😄

---

<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:** [September 24, 2020, 5:54pm UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/8 "2020-09-24T17:54:39Z")

</div>

I was going to do that, but I wanted to leave something to nerd snipe Paul. 😛

---

<div class="post-metadata">

**Author:** ![BillS](https://avatars.discourse-cdn.com/v4/letter/b/9fc348/32.png) [@BillS](https://forum.inductiveautomation.com/u/BillS)\
**Post date:** [September 24, 2020, 6:03pm UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/9 "2020-09-24T18:03:07Z")

</div>

I wrote and use the following:

```auto
def dictListToDataset(dictValues, defColumns=None):
	"""
	This will take a python list of dictionaries.  
	The dictionaries will contain Name/Value pairs where the Name field will become the Column Name for the resulting Ignition Dataset.
	Each dictionary row MUST match, it must contain the same Name/Value pairs with the Values being the same data type.
		
	Arguments:
		dictValues: The input list of dictionaries
	
	Results:
		Dataset: A built dataset containing all the Rows and Columns extracted from the dictionaries.
	"""
	logger = shared.MWES.Logging.getLog(lib=libName, src=srcName, autoMethod=True )

	data = []
	columns = defColumns
	for obj in dictValues:
		if columns == None:
			columns = obj.keys()
		row = []
		for column in columns:
			row.append(obj[column])
		data.append(row)
	if columns != None:
		logger.debug("Columns %s, Data %s" % (str(columns), str(data)))
		return system.dataset.toDataSet(columns,data)
	else:
		raise ValueError('could not find dictionary keys in %s' % (str(dictValues)))
		
def datasetToDictList(dataset):
	"""
	This will take an Igntion Dataset and convert it to a real python list of dictionaries. Unlike the PyDataset type.  
	The resulting dictionaries will contain Name/Value pairs where the Name field is derived from the Column Name in the Ignition Dataset.
		
	Arguments:
		dataset: The input Ignition Dataset
	
	Results:
		List of Dictionary Elements: A built list of dictionary rows containing all the Rows and Columns extracted from the dataset.
	"""
#	logger = shared.MWES.Logging.getLog(lib=libName, src=srcName, autoMethod=True )

	data = []
	columns = list(system.dataset.getColumnHeaders(dataset))
	pyDataset = system.dataset.toPyDataSet(dataset)

	return pyDatasetToDictList ( pyDataset, columns )	
	
def pyDatasetToDictList( *args, **kwargs ):
	"""
	This will take an Igntion PyDataset and convert it to a real python list of dictionaries. Unlike the PyDataset type.  
	The resulting dictionaries will contain Name/Value pairs where the Name field is derived from the Column Name in the Ignition PyDataset.
		
	Arguments:
		pyDataset: The input Ignition PyDataset
		columns: Optional list of column names to extract
	
	Results:
		List of Dictionary Elements: A built list of dictionary rows containing all the Rows and Columns extracted from the dataset.
	"""
#	logger = shared.MWES.Logging.getLog(lib=libName, src=srcName, autoMethod=True )

	pyDataset = None
	columns = None
	
	idx = 0
	sz = len(args)
	pyDataset = shared.MWES.Args.getParam( sz, idx, "PyDataset", False, True, args, kwargs )
	idx+=1
	columns = shared.MWES.Args.getParam( sz, idx, "Columns", None, False, args, kwargs )
	idx+=1

	data = []
	if pyDataset == None:
		return data
		
	if columns == None:
		columns = list(system.dataset.getColumnHeaders(system.dataset.toDataset(pyDataset)))
	for row in pyDataset:
		rowMap = {}
		for col in columns:
			rowMap[col] = row[col]
		data.append(rowMap)
	
	return data

```

It would have been really NICE if the pyDataset did the above for us!!!

---

<div class="post-metadata">

**Author:** ![jxlim](https://avatars.discourse-cdn.com/v4/letter/j/ce7236/32.png) [@jxlim](https://forum.inductiveautomation.com/u/jxlim)\
**Post date:** [September 25, 2020, 12:40am UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/10 "2020-09-25T00:40:37Z")

</div>

Thanks everyone for all the comment. I am still new to python, glad to learn all the different way to execute it.

---

<div class="post-metadata">

**Author:** ![mcarritt1](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mcarritt1/32/4262_2.png) [@mcarritt1](https://forum.inductiveautomation.com/u/mcarritt1)\
**Post date:** [September 28, 2020, 5:16pm UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/11 "2020-09-28T17:16:55Z")

</div>

this isn’t exactly your question, but I just figured it out recently and I think it’s relevant enough that it might help someone:

If you have a python dictionary that you want to save for later you can store it in a memory _document_ datatype tag like this:

```auto
myDict = {'some':'stuff'}
myJsonDict = system.util.jsonEncode(myDict)
system.tag.writeAsync(["Document Tag Path"], [myJsonDict])

```

and then later when you want to use it you can get your dictionary back like this:

```auto
myDict = dict(system.tag.read("Document Tag Path").value)

```

---

<div class="post-metadata">

**Author:** ![sfitze](https://avatars.discourse-cdn.com/v4/letter/s/ecccb3/32.png) [@sfitze](https://forum.inductiveautomation.com/u/sfitze)\
**Post date:** [October 1, 2020, 5:08pm UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/12 "2020-10-01T17:08:56Z")

</div>

You don’t need the inner comprehension. You can turn the zip directly into a dict.

```auto
NewDict = { 
 "Data %d" % i : dict(zip(pyData.columnNames,list(row))) 
     for i,row in enumerate(pyData)
}

```

---

<div class="post-metadata">

**Author:** ![Cameronin](https://avatars.discourse-cdn.com/v4/letter/c/9fc29f/32.png) [@Cameronin](https://forum.inductiveautomation.com/u/Cameronin)\
**Post date:** [May 26, 2022, 10:42am UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/13 "2022-05-26T10:42:56Z")

</div>

Hello humans

I’ve used @sfitze 's code, but I want my table to have this as data and read it as an array.  
But it’s making it an object of objects instead of an array of objects.  
I can fix it by right clicking in the properties and using ‘change to array’, but it reverts when the data changes.  
Is there a way to force it to interpret this as an array of objects?  
Thanks

---

<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:** [May 26, 2022, 11:46am UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/14 "2022-05-26T11:46:12Z")

</div>

Not in front of anything to test it, but I think that it needs to be a list comprehension:

```python
NewArray = [ 
            dict(zip(pyData.columnNames,list(row))) 
            for i,row in enumerate(pyData)
           ]

```

---

<div class="post-metadata">

**Author:** ![Cameronin](https://avatars.discourse-cdn.com/v4/letter/c/9fc29f/32.png) [@Cameronin](https://forum.inductiveautomation.com/u/Cameronin)\
**Post date:** [May 26, 2022, 3:55pm UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/15 "2022-05-26T15:55:22Z")

</div>

I actually managed this by using the my\_dictionary.values() as the return, instead of just my\_dictionary.  
Thanks for the response though! I didn’t get a reply notification for some reason 😛

---

<div class="post-metadata">

**Author:** ![mdemaris](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mdemaris/32/54639_2.png) [@mdemaris](https://forum.inductiveautomation.com/u/mdemaris)\
**Post date:** [September 19, 2023, 9:19pm UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/16 "2023-09-19T21:19:12Z")

</div>

Would something like this work in this situation?

Imagine several input boxes, numeric, text and drop down, then a button. The button will take all values from the input boxes, and move them into an array of objects. Now, a table is bound to this array. I manually created this array and entered the values: (the name, when copied and pasted, doesn't show, and neither does the object identifier: Name: temp\_table, object identifier: 0

```auto
[
  {
    "itemID": 1,
    "partNum": "xyz",
    "desc": "test",
    "price": 5,
    "quantity": 10
  }
]

```

![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/4/2/4221f32a225c3dcaa939e0a052ef37355133b37c.png)

the table displays the field names and values, as expected, BUT, I am not sure how to add another object to this array with the button's script. So I found this thread, which I think might have some value here.

Bottom line of the function I would like is each time the button is clicked, for the values to be added to the array... Hm, unless of course the values are the same...

---

<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:** [September 20, 2023, 10:25am UTC](https://forum.inductiveautomation.com/t/pydataset-to-dictionary/38968/17 "2023-09-20T10:25:23Z")

</div>

Even easier than you might think. Instead of static values, point them to your inputBoxes.  
EDIT: forgot to check for duplicates

```python
def runAction(self, event):
	data = system.util.jsonDecode(system.util.jsonEncode(self.getSibling("Table").props.data))
	# -or-
	# data = [dict(row) for row in self.getSibling("Table").props.data]
	
	newdata = {
	  	       "itemID": 2,
	  	       "partNum": "abc",
	  	       "desc": "test2",
	  	       "price": 7,
	  	       "quantity": 15
	         }
	
	if newdata not in data:	
		self.getSibling("Table").props.data.append(newdata)

	

```

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