Insert data in nested data structure - python

I have a variable like this:
self.playlist = {
"property_1":value_1,
"property_2":value_2,
...
"items":[]
}
where items array will contain objects of type self.playlist.
How can I insert data in self.playlist object? Let's have as input the playlist_items_sequence which i want to put data, the property_n and the value_n.
If playlist_items_sequence = [0,2,7] (zero will always be the first index, something like root) i want to put data to self.playlist["items"][2]["items"][7]["propery_n"] = value_n.
Another example: if playlist_items_sequence = [0,1,4,0] I want to execute self.playlist["items][1]["items"][4]["items"][0]["property_n"] = value_n
The simplest solution I thought is to use eval() and exec() for this data structure. But I am sure there will be a more clever solution.
Edit
If I do something like:
sub_playlist = self.playlist
for index_number in playlist_items_sequence[1:]:
sub_playlist = sub_playlist["items"][index_number]
sub_playlist["property_n"] = value_n
the self.playlist variable will not be updated.
But if I do:
exec_str = "self.playlist"
for index_number in playlist_items_sequence[1:]:
exec_str += "[\"items\"]["+str(index_number)+"]"
exec_str += "[\"property_n\"] = \""+str(value_n)"\""
exec(exec_str)
self.playlist variable will be updated.

Related

Get a dictionary from a class?

I want to:
Take a list of lists
Make a frequency table in a dictionary
Do things with the resulting dictionary
The class works, the code works, the frequency table is correct.
I want to get a class that returns a dictionary, but I actually get a class that returns a class type.
I can see that it has the right content in there, but I just can't get it out.
Can someone show me how to turn the output of the class to a dictionary type?
I am working with HN post data. Columns, a few thousand rows.
freq_pph = {}
freq_cph = {}
freq_uph = {}
# Creates a binned frequency table:
# - key is bin_minutes (size of bin in minutes).
# - value is freq_value which sums/counts the number of things in that column.
class BinFreq:
def __init__(self, dataset, bin_minutes, freq_value, dict_name):
self.dataset = dataset
self.bin_minutes = bin_minutes
self.freq_value = freq_value
self.dict_name = dict_name
def make_table(self):
# Sets bin size
# Counts how of posts in that timedelta
if (self.bin_minutes == 60) and (self.freq_value == "None"):
for post in self.dataset:
hour_dt = post[-1]
hour_str = hour_dt.strftime("%H")
if hour_str in self.dict_name:
self.dict_name[hour_str] += 1
else:
self.dict_name[hour_str] = 1
# Sets bins size
# Sums the values of a given index/column
if (self.bin_minutes == 60) and (self.freq_value != "None"):
for post in self.dataset:
hour_dt = post[-1]
hour_str = hour_dt.strftime("%H")
if hour_str in self.dict_name:
self.dict_name[hour_str] += int(row[self.freq_value])
else:
self.dict_name[hour_str] = int(row[self.freq_value])
Instantiate:
pph = BinFreq(ask_posts, 60, "None", freq_pph)
pph.make_table()
How can pph be turned into a real dictionary?
If you want the make_table function to return a dictionary, then you have to add a return statement at the end of it, for example: return self.dict_name.
If you then want to use it outside of the class, you have to assign it to a variable, so in the second snipped do: my_dict = pph.make_table().
Classes can't return things – functions in classes could. However, the function in your class doesn't; it just modifies self.dict_name (which is a misnomer; it's really just a reference to a dict, not a name (which one might imagine is a string)), which the caller then reads (or should, anyway).
In addition, there seems to be a bug; the second if block (which is never reached anyway) refers to row, an undefined name.
Anyway, your class doesn't need to be a class at all, and is easiest implemented with the built-in collections.Counter() class:
from collections import Counter
def bin_by_hour(dataset, value_key=None):
counter = Counter()
for post in dataset:
hour = post[-1].hour # assuming it's a `datetime` object
if value_key: # count using `post[value_key]`
counter[hour] += post[value_key]
else: # just count
counter[hour] += 1
return dict(counter.items()) # make the Counter a regular dict
freq_pph = bin_by_hour(ask_posts)
freq_cph = bin_by_hour(ask_posts, value_key="num_comments") # or whatever

Cleanest way to create instances of class dynamically

In caluclations.py I have one class called PowerPlant() with
def __init__(self, parameter1, parameter2, parameter3, ...)
and some functions belonging to the class e.g. calculate_supply(self, variable1, variable2).
I'd like to apply the calculations from calculations.py to some power plants stored in a csv file. So far i use the following way...
In simulation.py I read the data from the csv with pd.read_csv()
plant_data = pd.read_csv('plants.csv', sep = ';', index_col = False, encoding = 'latin')
Then i create a list of lists with
# Create list of lists from plant_data DataFrame
list_of_plants = [list(row) for row in plant_data.values]
Afterwards I create an instance of the Class PowerPlant with
## Outer loop: Iterate over all plants
for row in range(len(list_of_plants)):
ElectricityOut = []
Gains = []
...
# Initialise an instance of the plant
MyPowerPlant = PowerPlant(parameter1 = list_of_plants[row][0],
parameter2 = list_of_plants[row][1],
parameter3 = list_of_plants[row][2],
...)
# call some methods from calculations.py
...
Any ideas and suggetions how i could do this in a better and more professional way?
Maybe create a object for each plant?
You can iterate over a list like so, no need for range(len())
for row in list_of_plants:
ElectricityOut = []
Gains = []
...
# Initialise an instance of the plant
MyPowerPlant = PowerPlant(parameter1 = row[0],
parameter2 = row[0],
parameter3 = row[0],
...)
I'm not happy with accessing the list items with [item] e.g.
list_of_plants[row][0]
As far as i know there is no possibility to access lists via names (use dictionaries for that), but whats with namedTuples?
Is it possible to create instances of a class from namedTuples? If so i would change the list to a namedTuple...
Any suggestions?

Unable to retun multiple dicitonary sets in python

I'm querying a REST API url & I'm trying to return all the dictionary sets, but only able to return one key pair.
Dictionary Output in the print statement inside for loop is the expected output, when when returned only one set of key pair is appearing.
Expected Dictionary looks like:
{'IncidentID': 'IM10265'}
{'IncidentID': 'IM10266'}
{'IncidentID': 'IM10267'}
{'IncidentID': 'IM10268'}
Code:
import json , requests
sm1 = requests.get('http://Rest Url', auth=('XX','YY'))
z = json.loads(sm1.text)
def get_im_list():
incidentlist_access = z['content']
for im_data in incidentlist_access:
Access_imslist = im_data['Incident']
print(Access_imslist)
#print(type(Access_imslist))
#return Access_imslist
data = get_im_list()
#print(data)
So when when I'm un-commentating
return Access_imslist & print(data)
I'm only receiving the output as:
{'IncidentID': 'IM10265'}
not the complete dictionary.
Every time you loop through the data, Access_imslist gets overwritten, so when you (presumably) return Access_Imlist it's only returning the last value.
You need to create a data structure outside of the for loop, add each bit of data to it, then return that instead. Something like:
def get_im_list():
incident_data = []
incidentlist_access = z['content']
for im_data in incidentlist_access:
incident_data.append(im_data['Incident'])
return incident_data
hope that helps!
you need to define a variable list , and then append the Access_imslist values to that variable.
like this :
data = []
def get_im_list():
incidentlist_access = z['content']
for im_data in incidentlist_access:
Access_imslist = im_data['Incident']
data.append(Access_imslist)
print(data)

Python - Append to an array whose name is given by a string

I created multiply arrays and want to append something to them, but the user should choose which array he want append it to.
So to clarify what I mean: (The code down under is wrong, but I do not know how I could write it.)
x = []
y = []
def test(pName):
%s.append(1) %pName
test(y)
Edit:
#Jim Fasarakis-Hilliard
I am trying to program in PyGame.
Therefor I have to initalise all the images I want to use.
To not expand it, I wanted to create a function where you can easily append to any array you want to, so I do not have to create a new function every time I want to initalise new pictures.
My code looks like this atm.:
def loadImages(self,pName,pAnz,pScaleX,pScaleY):
for i in range(0,pAnz):
tux = pygame.transform.scale(pygame.image.load('./images/%s.png'),(pScaleX,pScaleY) % pName)
self.%s.append(tux) %pName
length_array = len(self.%s) %pName
return length_array
You could use globals, pass a string of the variable name to the function:
def test(pName):
globals()[pName].append(1)
test('y')
this, of course, relies on the name existing in the global scope.
You could put the array's in a dictionary. Assuming that there is a fixed number of arrays, the code would look something like this:
arrays = {}
arrays['x'] = []
arrays['y'] = []
def test(pName):
arrays[pName].append(1)
test('y')
You will want to check the user input, as a pName which is not a key in the dictionary will throw a key exception. If you want the arrays to be dynamic, you could do something like this:
arrays={}
def test(pName):
if pName not in arrays.keys():
arrays[pName]=[]
arrays[pName].append(1)
test('y')
If all you want is to be able to save your objects into different "namespaces", you can use dictionaries:
lists = {
"x": [],
"y": []
}
def test(pName):
lists[pName].append(1)
test("y")
Cleaner and easier to understand than using globals or similars IMHO.

Referencing a variable after separating it from a list

input = "12345_usa_wool_10x10_100_80.jpg"
def CleanData(input):
data = input.split('_')
sku = data[0]
country = data[1].capitalize()
material = data[2].capitalize()
size = data[3]
retail_price = data[4]
sale_price = data[5]
CleanData(input)
print (sku)
print (country)
I'm getting
NameError: name 'sku' is not defined
I tried to store all the values in the list I created to easily reference back to them later.
Such as if they wanted total savings I could then later make something like
def Saving()
total_saving = retail_price-sale_price
return total_saving
So I can later have a final output of something like:
print (sku+" "+country+" "+sale_price+" "+Saving())
I'm a beginner and self-learner so I figured this isn't too hard of a problem but I don't know how to have sku,country,material, etc. be able to be referenced publicly.
sku is defined in the CleanData function only, it does not have scope outside of that function.
I'd recommend using a dict object instead. E.g.,
def parseData(input):
data = input.split('_')
d = {}
d['sku'] = data[0]
d['country'] = data[1].capitalize()
d['material'] = data[2].capitalize()
d['size'] = data[3]
d['retail_price'] = data[4]
d['sale_price'] = data[5]
return d
myData = parseData(input)
print(myData['sku'])
print(myData['country'])
You can also directly construct the dict:
def parseData(input):
data = input.split('_')
d = {'sku': data[0],
'country': data[1].capitalize(),
'material': data[2].capitalize(),
'size': data[3],
'retail_price': data[4],
'sale_price': data[5]}
return d
What you have is python scope, sku, and all the other variables assigned in the function, are local to the function. If you want them to be global, then mark them as such:
def CleanData(input):
data = input.split('_')
global sku
sku = data[0]
.... and so on
However, it is generally not a good idea to use global variables in this way. We want our functions to be encapsulated so that they can be used in many programs. The problem with using globals is that you have to know that the name is not going to be used for something else in the program. If you need to reuse the code across programs then that will break.
The solution is to return some sort of container. For example it could be a dictionary, a list, or a tuple. Here is an example using a tuple:
def CleanData(input):
data = input.split('_')
# sku, country, material, size, retail_price, sale_price
return (data[0],
data[1].capitalize(),
data[2].capitalize(),
data[3],
data[4],
data[5])
sku, country, material, size, retail_price, sale_price = CleanData(input)
print (sku)
print (country)
You could probably simplify this further by just returning data. In addition you might wish to test len(data) to ensure you have the correct number of fields.

Categories

Resources