I'm new to python and came across this segment of code. Can someone help me with the syntax here? Maybe provide some comments on each line to how it's working? xs is a list that contains dates.
data = {}
for title, d in tmpdata.items():
data[title] = [x in d and d[x][statid] or 0 for x in xs]
data[title][-1] = maxs[statid]
If I had to guess, I'd say the most perplexing line to someone new to Python must be:
data[title] = [x in d and d[x][statid] or 0 for x in xs]
There is a lot going on here, and some of it uses a style that, although safe in this instance, is no longer recommended. Here is a more verbose form:
data[title] = []
for x in xs:
if x in d and d[x][statid]:
data[title].append(d[x][statid])
else:
data[title].append(0)
The construct condition and value-if-condition-is-true or value-if-condition-is-false is an old-style form of the C ternary form condition ? value-if-condition-is-true : value-if-condition-is-false. The given Python expression hides a latent bug that can crop up if the value-if-condition-is-true is evaluated by Python as a "false-y" value - 0, [], () are all values that would be considered as false if used in a conditional expression, so you might have a problem if your value-if-condition-is-true turned out to be one of these. As it happens in this case, if d[x][statid] is 0, then we would assume a False result and go on and add a 0 to the list, which would be the right thing to do anyway. If we could just edit the verbose form, the simplest would be to remove the and d[x][statid] as in:
data[title] = []
for x in xs:
if x in d:
data[title].append(d[x][statid])
else:
data[title].append(0)
Or use the new Python ternary form (which gives some people a rash, but I have grown accustomed to it - the ternary form, not the rash), which is written as:
value-if-condition-is-true if condition else value-if-condition-is-false
Or substituting into our verbose form:
data[title] = []
for x in xs:
data[title].append(d[x][statid] if x in d else 0)
So lastly, the list comprehension part. Whenever you have this kind of loop:
listvar = []
for some-iteration-condition:
listvar.append(some-iteration-dependent-value)
You can rewrite it as:
listvar = [some-iteration-dependent-value for some-iteration-condition]
and this form is called a list comprehension. It creates a list by following the iteration condition and evaluating the value for each iteration.
So you can now see how the original statement would be written. Because of the possible latent bug inherent in the old-style condition and true-value or false-value, the ternary form or an explicit if-then-else is the preferred style now. The code should be written today as:
data[title] = [d[x][statid] if x in d else 0 for x in xs]
An explanation of the code is:
Initialize data to the empty dictionary
Loop through the key-value pairs in the dictionary tmpdata, calling the key title and the value d
a. Add a new key-value pair to the data dictionary whose key is title and whose value is a list of the following: for each x in some (global?) list xs, the value x itself if d[x][statid] is truthy otherwise 0.
b. Overwrite the last cell of this new value with maxs[statid]
There are some interesting pythonic structures here - list comprehensions and the and/or form of the conditional expression.
# Data initialization
data = {}
# for over all the element of the dictionary tmpdata
# title will get the index and d the data of the current element
for title, d in tmpdata.items():
#data[title]= a list containing each x contained in list xs
# the x value or 0 depening on the condition "d[x][statid]"
data[title] = [x in d and d[x][statid] or 0 for x in xs]
# Assign the value maxs[statid] to the last cell ( I think but not too sure)
data[title][-1] = maxs[statid]
Related
I have a list containing:
NewL = [(1.1,[01,02]),(1.2,[03,04]),(1.3,[05,06])]
and i used enumerate to obtain the list as above where the square brackets containing [01,02],[03,04] and [05,06] are generally obtained from another list. I'll show it just in case:
L = [[01,02],[03,04],[05,06]]
and initially the output list is just:
OutputList = [1.1,1.2,1.3]
i used enumerate on both of this list to get what i have as the first list i've written above.
The problem i'm facing now is, let's say i want to only output the value for [05,06] which is 1.3 from the NewL. How would i do that? I was thinking of something like:
for val in NewL:
if NewL[1] == [05,06]:
print NewL[0]
but it's totally wrong as cases might change where it's not necessary always be [05,06] as it can be obtaining value for [03,04] and [01,02] too. I'm pretty new using enumerate so I'll appreciate any help for this.
The for loop should like this:
for val in NewL:
if val[1] == [5,6]:
print val[0]
It will print 1.3
I'm not sure I understand the question, so I will extrapolate what you need:
Given your 2 intial lists:
L = [[01,02],[03,04],[05,06]]
OutputList = [1.1,1.2,1.3]
you can generate your transformed list using:
NewL = list(zip(OutputList, L))
then, given 1 item from L, if you want to retrieve the value from OutputList:
val = [x for x, y in NewL if y == [05,06]][0]
But it would be a lot easier to just do:
val = OutputList[L.index([05,06])]
Note that both those expressions will raise an IndexError if the searched item is not found
I'm parsing JSON objects and found this sample line of code which I kind of understand but would appreciate a more detailed explanation of:
for record in [x for x in records.split("\n") if x.strip() != '']:
I know it is spliting records to get individual records by the new line character however I was wondering why it looks so complicated? is it a case that we can't have something like this:
for record in records.split("\n") if x.strip() != '']:
So what do the brackets do []? and why do we have x twice in x for x in records.split....
Thanks
The "brackets" in your example constructs a new list from an old one, this is called list comprehension.
The basic idea with [f(x) for x in xs if condition] is:
def list_comprehension(xs):
result = []
for x in xs:
if condition:
result.append(f(x))
return result
The f(x) can be any expression, containing x or not.
That's a list comprehension, a neat way of creating lists with certain conditions on the fly.
You can make it a short form of this:
a = []
for record in records.split("\n"):
if record.strip() != '':
a.append(record)
for record in a:
# do something
The square brackets ( [] ) usually signal a list in Python.
I have a list of lists that looks like:
c = [['470', '4189.0', 'asdfgw', 'fds'],
['470', '4189.0', 'qwer', 'fds'],
['470', '4189.0', 'qwer', 'dsfs fdv']
...]
c has about 30,000 interior lists. What I'd like to do is eliminate duplicates based on the 4th item on each interior list. So the list of lists above would look like:
c = [['470', '4189.0', 'asdfgw', 'fds'],['470', '4189.0', 'qwer', 'dsfs fdv'] ...]
Here is what I have so far:
d = [] #list that will contain condensed c
d.append(c[0]) #append first element, so I can compare lists
for bact in c: #c is my list of lists with 30,000 interior list
for items in d:
if bact[3] != items[3]:
d.append(bact)
I think this should work, but it just runs and runs. I let it run for 30 minutes, then killed it. I don't think the program should take so long, so I'm guessing there is something wrong with my logic.
I have a feeling that creating a whole new list of lists is pretty stupid. Any help would be much appreciated, and please feel free to nitpick as I am learning. Also please correct my vocabulary if it is incorrect.
I'd do it like this:
seen = set()
cond = [x for x in c if x[3] not in seen and not seen.add(x[3])]
Explanation:
seen is a set which keeps track of already encountered fourth elements of each sublist.
cond is the condensed list. In case x[3] (where x is a sublist in c) is not in seen, x will be added to cond and x[3] will be added to seen.
seen.add(x[3]) will return None, so not seen.add(x[3]) will always be True, but that part will only be evaluated if x[3] not in seen is True since Python uses short circuit evaluation. If the second condition gets evaluated, it will always return True and have the side effect of adding x[3] to seen. Here's another example of what's happening (print returns None and has the "side-effect" of printing something):
>>> False and not print('hi')
False
>>> True and not print('hi')
hi
True
Use pandas. I assume you have better column names as well.
c = [['470', '4189.0', 'asdfgw', 'fds'],
['470', '4189.0', 'qwer', 'fds'],
['470', '4189.0', 'qwer', 'dsfs fdv']]
import pandas as pd
df = pd.DataFrame(c, columns=['col_1', 'col_2', 'col_3', 'col_4'])
df.drop_duplicates('col_4', inplace=True)
print df
col_1 col_2 col_3 col_4
0 470 4189.0 asdfgw fds
2 470 4189.0 qwer dsfs fdv
You have a significant logic flaw in your current code:
for items in d:
if bact[3] != items[3]:
d.append(bact)
this adds bact to d once for every item in d that doesn't match. For a minimal fix, you need to switch to:
for items in d:
if bact[3] == items[3]:
break
else:
d.append(bact)
to add bact once if all items in d don't match. I suspect this will mean your code runs in more sensible time.
On top of that, one obvious performance improvement (speed boost, albeit at the cost of memory usage) would be to keep a set of fourth elements you've seen so far. Lookups on the set use hashes, so the membership test (highlighted) will be much quicker.
d = []
seen = set()
for bact in c:
if bact[3] not in seen: # membership test
seen.add(bact[3])
d.append(bact)
how can i specify or determine the values in my objects in python if it has this value [] or it has [<Booking: arab>],
let us say that in my queryset, i filter a value that not exist in my objects.
here is what i have done : this date_select has no data
>>> x = Booking.objects.filter(date_select='2011-12-3')
>>> print x
[]
>>> if x == None:
... print 'none'
...
>>>
is it [] not equal to None?
when i try a date_select that has data
>>> x = Booking.objects.filter(date_select='2011-12-2')
>>> print x
[<Booking: arab>, <Booking: arab>, <Booking: vvv>]
>>> if x == None:
... print 'none'
...
>>>
i just want to determine if x has a data or not...
can anyone can give me an idea about my case?
thanks in advance
If you want to know if your queryset returned any results, call the exists method.
x = Booking.objects.filter(date_select='2011-12-3')
if x.exists():
# There are some results from this query set
If you want to know how many items, you can use count
x = Booking.objects.filter(date_select='2011-12-3')
print x.count()
No, [] is not equal to None. [] is an empty list - a list with no content but that exists nonetheless and can come to have some elements. None is a value representing "nothing" - when you find the None value, it meas something like "this variable has no relevant content". Since empty lists can be relevant content - for example, the empty list can be the initial state of a list which will accumulate elements over time - then there is no sense in assuming that [] == None.
armonge gave you the response: just use the list as the condition, because empty lists are "falsy" - that is, empty lists has the same effect of False when used as a condition for an if, while etc. If you want to execute something when the list does not have some content, just negate it:
if not x:
print 'empty list (is not None)'
BTW, a question: are you used to program in Lisp? This is the only language where an empty list is equivalent to the "None type" (in this case, nil).
You just need
if queryset:
print 'not empty'
In python how can i change the value of references contained inside a list ?
For example in the following code
x = 'stack'
y = 'exchange'
l = [x,y]
l[1] = 'overflow'
The last line would actually replace y with 'overflow' but what I want to do is change the reference contained at l[1] to 'overflow' how can I achieve the same ?
PS : y = 'overflow' is not an accepted answer :P
The context probably will make the problem clearer there are 50 variable that I have inside a list initialised to zero and I want them to set their values at run-time.so that when at a later point of time I do a print variable50 , i get the new value not zero.
You do rebind reference at l[1] to 'overflow' with l[1] = 'overflow'. If you want to actually modify the string object, you can't. Strings are immutable.
"change the value of references" is awkward phrasing and there are two separate things that I can imagine that you mean:
1) cause the element of the list to refer to something else; but that's what your example does and is what you say you don't want.
2) cause the referred-to element of the list to change. The referred-to element is an object, so this is only possible by invoking code that changes the object's state. Python's str type is immutable, so no such code exists for the example situation.
What are you really trying to do? Idiomatic Python code embraces reference semantics rather than trying to fight them.
You want to add a new element to your list and sort it on position 1? That can be achieved with basic list functions.. Just a question why aren't you using dictionaries?
Is this interesting ?
x = 'stack'
y = 'exchange'
z = 'overflow'
l = [x, y]
l
['stack', 'exchange']
use python's swap
y, z = z, y
but then, you have to re-assign the list
l = [x, y]
l
['stack', 'overflow']