Declaring an object within (vs. outside) a while loop - python-2.7

Given the python 2.7 code below:
# faultReportObj = {}
flatDataObj = []
while row:
faultReportObj = {}
faultReportObj['MessageTime'] = row['MessageTime']
faultReportObj['Event'] = row['Event']
faultReportObj['Subsystem'] = row['Subsystem']
faultReportObj['UnifiedFaultCode'] = row['UnifiedFaultCode']
faultReportObj['FaultDescription'] = row['FaultDescription']
faultReportObj['FaultDetails'] = row['FaultDetails']
faultReportObj['FirstOccurrenceDateTime'] = row['FirstOccurrenceDateTime']
faultReportObj['LastOccurrenceDateTime'] = row['LastOccurrenceDateTime']
faultReportObj['OccurrenceCount'] = row['OccurrenceCount']
print "current row:"
pp.pprint(faultReportObj)
flatDataObj.append(faultReportObj)
row = cursor.fetchone()
conn.close()
pp.pprint(flatDataObj)
If I declare faultReportObj outside the while loop, I get (say) 96 entries in flatDataObj that are all identical to the very last row returned by the query. Note that the pprint statement within the while loop prints the expected (varying) results.
If, as above, I declare faultReportObj inside the loop, flatDataObj is loaded correctly.
Why???? Why is the very last row returned being propagated throughout the entire list?
Thanks!

This is due to list.append inserting a reference to faultReportObj and not copying the value of the dict.
Another way of looking at it:
If you define faultReportObj before the loop, the following occurs:
Create a new dict.
Populate it.
Append a reference to the dict into the list.
Change the dict's content.
Append another reference to the same dict.
etc.
Here's a short piece of code that exemplifies this property:
>>> d = {}
>>> l = []
>>> l.append(d)
>>> d[1] = 2
>>> l
[{1: 2}]
What you want is for step one (Create a new dict) to happen in every iteration of the loop, so that you append a different dict every time.

Related

Python: How to add tuple to an empty list?

I've looked around at other posts on here for a solution to my problem but none of them seems to work for me. I want to append a tuple to (what starts out as) an empty list. I've checked my code and it looks like whenever I try to just append my tuple it turns the list into a NoneType object. Here's what I've got:
list_of_pairs = []
for player in standings:
opponent = standings[standings.index(player) + 1]
matchup = (player[0:2] + opponent[0:2])
list_of_pairs = list_of_pairs.append(matchup)
print "ADDED TO LIST: " + str(list_of_pairs)
Each player in the standings list contains a tuple with four elements. I've tried using index and re-assigning list_of_pairs = [list_of_pairs, matchup], but nothing seems to be returning the right thing (i.e. [(player),(next player), (another player), (etc.)]. Every time I print "added to list" I just get ADDED TO LIST: None. I've checked matchup as well and it's definitely storing the first two values of the respective players fine. Any ideas?
This is because appending an element to a list returns None, which you are then printing when you do:
list_of_pairs = list_of_pairs.append(matchup)
print "ADDED TO LIST: " + str(list_of_pairs)
For example:
>>> a = []
>>> b = a.append('hello')
>>> print a
['hello']
>>> print b
None

How do I extract part of a tuple that's duplicate as key to a dictionary, and have the second part of the tuple as value?

I'm pretty new to Python and Qgis, right now I'm just running scripts but I my end-goal is to create a plugin.
Here's the part of the code I'm having problems with:
import math
layer = qgis.utils.iface.activeLayer()
iter = layer.getFeatures()
dict = {}
#iterate over features
for feature in iter:
#print feature.id()
geom = feature.geometry()
coord = geom.asPolyline()
points=geom.asPolyline()
#get Endpoints
first = points[0]
last = points[-1]
#Assemble Features
dict[feature.id() ]= [first, last]
print dict
This is my result :
{0L: [(355277,6.68901e+06), (355385,6.68906e+06)], 1L: [(355238,6.68909e+06), (355340,6.68915e+06)], 2L: [(355340,6.68915e+06), (355452,6.68921e+06)], 3L: [(355340,6.68915e+06), (355364,6.6891e+06)], 4L: [(355364,6.6891e+06), (355385,6.68906e+06)], 5L: [(355261,6.68905e+06), (355364,6.6891e+06)], 6L: [(355364,6.6891e+06), (355481,6.68916e+06)], 7L: [(355385,6.68906e+06), (355501,6.68912e+06)]}
As you can see, many of the lines have a common endpoint:(355385,6.68906e+06) is shared by 7L, 4L and 0L for example.
I would like to create a new dictionary, fetching the shared points as a key, and having the second points as value.
eg : {(355385,6.68906e+06):[(355277,6.68901e+06), (355364,6.6891e+06), (355501,6.68912e+06)]}
I have been looking though list comprehension tutorials, but without much success: most people are looking to delete the duplicates, whereas I would like use them as keys (with unique IDs). Am I correct in thinking set() would still be useful?
I would be very grateful for any help, thanks in advance.
Maybe this is what you need?
dictionary = {}
for i in dict:
for j in dict:
c = set(dict[i]).intersection(set(dict[j]))
if len(c) == 1:
# ok, so now we know, that exactly one tuple exists in both
# sets at the same time, but this one will be the key to new dictionary
# we need the second tuple from the set to become value for this new key
# so we can subtract the key-tuple from set to get the other tuple
d = set(dict[i]).difference(c)
# Now we need to get tuple back from the set
# by doing list(c) we get list
# and our tuple is the first element in the list, thus list(c)[0]
c = list(c)[0]
dictionary[c] = list(d)[0]
else: pass
This code attaches only one tuple to the key in dictionary. If you want multiple values for each key, you can modify it so that each key would have a list of values, this can be done by simply modifying:
# some_value cannot be a set, it can be obtained with c = list(c)[0]
key = some_value
dictionary.setdefault(key, [])
dictionary[key].append(value)
So, the correct answer would be:
dictionary = {}
for i in a:
for j in a:
c = set(a[i]).intersection(set(a[j]))
if len(c) == 1:
d = set(a[i]).difference(c)
c = list(c)[0]
value = list(d)[0]
if c in dictionary and value not in dictionary[c]:
dictionary[c].append(value)
elif c not in dictionary:
dictionary.setdefault(c, [])
dictionary[c].append(value)
else: pass
See this code :
dict={0L: [(355277,6.68901e+06), (355385,6.68906e+06)], 1L: [(355238,6.68909e+06), (355340,6.68915e+06)], 2L: [(355340,6.68915e+06), (355452,6.68921e+06)], 3L: [(355340,6.68915e+06), (355364,6.6891e+06)], 4L: [(355364,6.6891e+06), (355385,6.68906e+06)], 5L: [(355261,6.68905e+06), (355364,6.6891e+06)], 6L: [(355364,6.6891e+06), (355481,6.68916e+06)], 7L: [(355385,6.68906e+06), (355501,6.68912e+06)]}
dictionary = {}
list=[]
for item in dict :
list.append(dict[0])
list.append(dict[1])
b = []
[b.append(x) for c in list for x in c if x not in b]
print b # or set(b)
res={}
for elm in b :
lst=[]
for item in dict :
if dict[item][0] == elm :
lst.append(dict[item][1])
elif dict[item][1] == elm :
lst.append(dict[item][0])
res[elm]=lst
print res

Creating a Dictionary from a while loop (Python)

How can I create a Dictionary from my while loop below? infile reads from a file called input, which has the following content:
min:1,23,62,256
max:24,672,5,23
sum:22,14,2,3,89
P90:23,30,45.23
P70:12,23,24,57,32
infile = open("input.txt", "r")
answers = open("output.txt", "w")
while True:
line = infile.readline()
if not line: break
opType = line[0:3]
numList = (line[4:len(line)])
numList = numList.split(',')
What I'm trying to do is basically 2 lists, one that has the operation name (opType) and the other that has the numbers. From there I want to create a dictionary that looks like this
myDictionary = {
'min': 1,23,62,256,
'max': 24,672,5,23,
'avg': 22,14,2,3,89,
'P90': 23,30,45.23,
'P70': 12,23,24,57,32,
}
The reason for this is that I need to call the operation type to a self-made function, which will then carry out the operation. I'll figure this part out. I currently just need help making the dictionary from the while loop.
I'm using python 2.7
Try the following code.
I believe, you would need the 'sum' also in the dictionary. If not, just add a condition to remove it.
myDictionary = {}
with open('input.txt','r') as f:
for line in f:
x = line.split(':')[1].rstrip().split(',')
for i in xrange(len(x)):
try:
x[i] = int(x[i])
except ValueError:
x[i] = float(x[i])
myDictionary[line.split(':')[0]] = x
print myDictionary

Multidict in python not working ?? How to create it?

I want to create an python multi dimensional dictionary :-
Currently i am doing like this
multidict = {}
IN LOOP
mulitdict[i] = data
if loop runs ten times I am getting same value in all index..
Eg:
I want to have like this
multidict {0 : {'name':name1, 'age' : age1}, 1: {'name':name2, 'age' : age2}
but i am getting as shown below
multidict {0 : {'name':name1, 'age' : age1}, 1: {'name':name1, 'age' : age1}
I also tried the default dict also....but every time i get same value in all index. What is the problem?
Tried code :
csv_parsed_data2 = {}
with open('1112.txt') as infile:
i =0
for lineraw in infile:
line = lineraw.strip()
if 'sample1 ' in line:
### TO GET SOURCE ROUTER NAME ###
data['sample1'] = line[8:]
elif 'sample2- ' in line:
### TO GET DESTINATION ROUTER NAME ###
data['sample2'] = line[13:]
elif 'sample3' in line:
### TO GET MIN,MAX,MEAN AND STD VALUES ###
min_value = line.replace("ms"," ")
min_data = min_value.split(" ")
data['sample3'] = min_data[1]
csv_parsed_data2[i] = data
i = i + 1
print i,'::',csv_parsed_data2,'--------------'
print csv_parsed_data2,' all index has same value'
any efficient way to do this??
It sounds you are assigning the same data dict to each of the values of your outer multidict, and just modifying the values it holds on each pass through the loop. This will result in all the values appearing the same, with the values from the last pass through the loop.
You probably need to make sure that you create a separate dictionary object to hold the data from each value. A crude fix might be to replace multidict[i] = data with multidict[i] = dict(data), but if you know how data is created, you can probably do something more elegant.
Edit: Seeing your code, here's a way to fix the issue:
csv_parsed_data2 = {}
with open('1112.txt') as infile:
i =0
data = {} # start with empty data dict
for lineraw in infile:
line = lineraw.strip()
if 'sample1 ' in line:
### TO GET SOURCE ROUTER NAME ###
data['sample1'] = line[8:]
elif 'sample2- ' in line:
### TO GET DESTINATION ROUTER NAME ###
data['sample2'] = line[13:]
elif 'sample3' in line:
### TO GET MIN,MAX,MEAN AND STD VALUES ###
min_value = line.replace("ms"," ")
min_data = min_value.split(" ")
data['sample3'] = min_data[1]
csv_parsed_data2[i] = data
data = {} # after saving a reference to the dict, reinitialize it
i = i + 1
print i,'::',csv_parsed_data2,'--------------'
print csv_parsed_data2,' all index has same value'
To understand what was going on, consider this simpler situation, where I a values in a dictionary after saving a reference to it when it had some older values:
my_dict = { "foo": "bar" }
some_ref = my_dict
print some_ref["foo"] # prints "bar"
my_dict["foo"] = "baz"
print some_ref["foo"] # prints "baz", since my_dict and some_ref refer to the same object
print some_ref is d # prints "True", confirming that fact
In your code, my_dict was data and some_ref were all the values of csv_parsed_data2. They would all end up being references to the same object, which would hold whatever the last values assigned to data were.
Try this:
multidict = {}
for j in range(10):
s = {}
s['name'] = raw_input()
s['age'] = input()
multidict[j] = s
This will have the desired result

django, trying to manipulate queryset and return to template

I'm trying to perform an operation on all the elements from a single field of a model, but I'm getting an error:
list indices must be integers, not tuple
Here's my index function in views.py:
design_list = Design.objects.values_list().order_by('-date_submitted')[:10]
x=list(design_list)
for i in x:
b = list(x[i]) # ERROR RELATES TO THIS LINE
c = b[2]
b[2] = datetimeConvertToHumanReadable(c)
new_list[i] = b
return render_to_response('index.html', {
'design_list': new_list,
})
I'm sure this is a common problem, does anyone know what I'm doing wrong?
Python is not C - the for x in y loop does not loop over indices, but over the items themselves.
design_list is a list of tuples, so you can treat it as such. Tuples are immutable, therefore you'll need to create a new list. A list comprehension would probably be best.
# Create a new list of tuples
new_list = [row[:2] + (datetimeConvertToHumanReadable(row[2]),) + row[3:]
for row in x]
However, it doesn't seem like you really need to use tuples, since you were confused by the error. If this is the case, then don't use values_list (which returns tuples), but just use order_by, and reference the field directly (I'll assume it's called date_submitted).
design_list = Design.objects.order_by('-date_submitted')[:10]
x=list(design_list)
for row in x:
row.date_submitted = datetimeConvertToHumanReadable(row.date_submitted)
return render_to_response('index.html', {
'design_list': x,
})
for i in x: iterates over the values of x, not the indices. Without analyzing the intent behind the code (and the proper use of QuerySets), the line could be changed to:
b = list(i)
to avoid this particular error.