'datetime.datetime' object is not subscriptable - python

I've checked every other post about this, but none can fix my issue.
I made a list that holds tuples with an id and a datetime object. Everytime I try to clean up the list with:
last_encounters = [item for item in last_encounters if item[1] < datetime.utcnow]
I get the error that 'datetime.datetime' object is not subscriptable. It's getting pretty annoying, I tried dicts.. didn't work.
Also tested the item[1], according to my print it is a datetime.
Even tried changing it to (x,y) for x,y in last_encounters if y < ... also did NOT work.
Some useful code:
list = []
d_t = datetime.utcfromtimestamp(9000000)
list += [('lel', d_t)]
list = [item for item in list if item[1] < datetime.utcnow]
I hope someone can tell me what I am doing wrong here.
Thanks in advance,
Kevin

When you do last_encounters += (a, b), you are adding two sequences together, last_encounters and (a,b). This means you end up with a and b stuck on the end of the list, rather than just adding the tuple to the list.
There are two options to fix your problem:
Add a sequence containing your tuple:
last_encounters += [(d["id"], d["d_t"])]
Or preferably, use the append method:
last_encounters.append((d["id"], d["d_t"]))

It looks like your problem is the way you add the tuple to the list. Here is an example to show the problem :
l = []
l += ("a", "b")
print l
l = []
l.append( ("a", "b"))
print l
Which gives :
>>> ['a', 'b']
>>> [('a', 'b')]
So list+=tuple is equivalent to calling list.extend(tuple) and not list.append(tuple) which is what you want.
A side note on the meaning of the exception that was raised :
X is not subscriptable means that your are trying to call that syntax X[some int] while the object doesn't support it.

Try calling utcnow as a method utcnow():
last_encounters = [item for item in last_encounters if item[1] < datetime.utcnow()]
I couldn't reproduce your error with a version of your code, but a version with items in the list lead to this fix.

Related

Why does [:1] work in a for loop but not [0] in python?

I just had a quick question about the difference between [:1] and [0]
The following program parses a text document and puts all instances of email addresses in said txt document in a dictionary, and then creates a list of tuples from this dictionary, then sorts the list and prints out the email with the most instances. Please read the last 2 lines of code on this program:
emails = dict()
fname = input('Enter file name: ')
try:
fhand = open(fname)
except:
print("sorry can't do that")
quit()
for line in fhand:
if not line.startswith("From "):
continue
line = line.split()
emails[line[1]] = emails.get(line[1], 0) + 1
tmp = list()
for k, v in emails.items():
newtup = (v, k)
tmp.append(newtup)
tmp = sorted(tmp, reverse = True)
for v, k in tmp[:1]:
print(k, v)
Specifically, the last 2 lines of this program:
for v, k in tmp[:1]:
print(k, v)
Works perfectly. But when I tried to do the same thing with this syntax:
for v, k in tmp[0]:
print(k, v)
I get the following traceback:
TypeError: cannot unpack non-iterable int object
I guess that [0] is in some way, not the same as [:1]? Why does tmp[:1] work but tmp[0] doesn't in a for loop?
I have no complaints since my program is running perfectly with the tmp[:1] syntax, but why doesn't it work with the tmp[0] syntax? Are they not the same thing?
Thanks for your time and for reading this if you've come this far!
You need to read about Python list indexing and slicing, as that is the difference between the two.
tmp[:1]:
This is list slicing syntax. This general form of this syntax is like this,
list_object[start_idx: end_index]
This returns a sliced list with elements starting from(including) start_idx and ending with end_idx(not inclusive, so one less than this value).
So in your question tmp[:1] returns a sublist(which is considered an iterable) with elements at 0. Since this is an iterable it is acceptable to iterate over in a for loop.
tmp[0]:
This is list indexing syntax. The general form is,
list_object[element_idex]
This returns an element at that index. The returned value may/may not be an iterable (it depends on what the list is composed of). In your case, tmp[0] returns the first element of the list.
Emmm, here is an example.
>> tmp = [1, 2, 3]
>> tmp[:1]
[1]
>> tmp[0]
1
>> type([1])
list
>> type(1)
int
As you see, [:1] and [0] produces different stuff. [:1] makes list, [0] returns first element. Why you didn't try it just yourself?
Also made an example just for you :)
>> tmp = [(1,1),(2,2),(3,3)]
>> tmp[:1]
[(1, 1)]
>> tmp[0]
(1, 1)
>> for k,v in [(1, 1)]: pass
>> for k,v in (1, 1): pass
TypeError: cannot unpack non-iterable int object
Iteration like this does not make sence at all: for k,v in (1, 1):.
Ok. Makes sense.
>>> tmp = [1, 2, 3]
>>> tmp[0]
1
>>> tmp[:1]
[1]
where tmp[0] could be any object, like something that can't be iterated through, like in my case, a tuple.

how to convert a set in python into a dictionary

I am new to python and trying to convert a Set into a Dictionary. I am struggling to find a way to make this possible. Any inputs are highly appreciated. Thanks.
Input : {'1438789225', '1438789230'}
Output : {'1438789225':1, '1438789230':2}
Use enumerate() to generate a value starting from 0 and counting upward for each item in the dictionary, and then assign it in a comprehension:
input_set = {'1438789225', '1438789230'}
output_dict = {item:val for val,item in enumerate(input_set)}
Or a traditional loop:
output_dict = {}
for val,item in enumerate(input_set):
output_dict[item] = val
If you want it to start from 1 instead of 0, use item:val+1 for the first snippet and output_dict[item] = val+1 for the second snippet.
That said, this dictionary would be pretty much the same as a list:
output = list(input_set)
My one-liner:
output = dict(zip(input_set, range(1, len(s) + 1)))
zip mixes two lists (or sets) element by element (l1[0] + l2[0] + l1[1] + l2[1] + ...).
We're feeding it two things:
the input_set
a list from 1 to the length of the set + 1 (since you specified you wanted to count from 1 onwards, not from 0)
The output is a list of tuples like [('1438789225', 1), ('1438789230', 2)] which can be turned into a dict simply by feeding it to the dict constructor... dict.
But like TigerhawkT3 said, I can hardly find a use for such a dictionary. But if you have your motives there you have another way of doing it. If you take away anything from this post let it be the existence of zip.
an easy way of doing this is by iterating on the set, and populating the result dictionary element by element, using a counter as dictionary key:
def setToIndexedDict(s):
counter = 1
result = dict()
for element in s:
result[element] = counter #adding new element to dictionary
counter += 1 #incrementing dictionary key
return result
My Python is pretty rusty, but this should do it:
def indexedDict(oldSet):
dic = {}
for elem,n in zip(oldSet, range(len(oldSet)):
dic[elem] = n
return dic
If I wrote anything illegal, tell me and I'll fix it. I don't have an interpreter handy.
Basically, I'm just zipping the list with a range object (basically a continuous list of numbers, but more efficient), then using the resulting tuples.
Id got with Tiger's answer, this is basically a more naive version of his.

Python: TypeError: list indices must be integers, not list

I've got two lists of coordinates, they look like this:
list_kp2_ok:
[[1185.60009765625, 933.6000366210938], [1310.4000244140625, 828.0000610351562], [1067.0, 979.0], [1310.0, 828.0], [1423.2000732421875, 814.800048828125], [1306.0, 828.0], [3634.0, 605.0], [1308.0960693359375, 827.7120971679688], [1422.7200927734375, 815.0400390625], [1185.1199951171875, 933.1200561523438], [1186.56005859375, 923.0400390625], [1306.3681640625, 829.4401245117188], [1194.393798828125, 839.80810546875], [1187.1361083984375, 922.7520751953125], [1082.8800048828125, 849.6000366210938]]
list_kp2_2_ok:
[[835.0, 1201.0], [1086.0, 850.0], [1187.0, 924.0], [1197.0, 839.0], [1310.0, 828.0], [3634.0, 605.0], [1195.2000732421875, 838.800048828125], [1308.0, 828.0000610351562], [1084.800048828125, 849.6000366210938], [1310.4000244140625, 828.0000610351562], [1186.800048828125, 924.0000610351562], [1296.0, 956.4000244140625], [1082.8800048828125, 849.6000366210938], [1072.800048828125, 944.6400146484375], [1083.4560546875, 850.1760864257812], [1187.1361083984375, 922.7520751953125], [3633.984375, 606.528076171875], [1082.4193115234375, 850.1761474609375], [1306.3681640625, 829.4401245117188], [1181.9521484375, 966.2977294921875], [1306.3682861328125, 828.6107788085938]]
Now I need to check if there are any same coordinates on both lists and create a new list of them.
So I wrote:
list_wsp=[]
count=0
count1=0
print type(count)
print type(count1)
for count in list_kp2_ok:
for count1 in list_kp2_2_ok:
if list_kp2_ok[count]==list_kp2_2_ok[count1]:
list_wsp.append(list_kp2_ok[count])
count1=count1+1
if count1==len(list_kp2_2_ok)-1:
break
count=count+1
if count==len(list_kp2_ok)-1:
break
and...
TypeError: list indices must be integers, not list
I don't know what's wrong, couldn't find a solution...
Could anyone help me, please?
Maybe there's a simplier way to do such a thing?
Python's for loop is not indexed-based, it really iterates on the sequence (or any iterable). So in this code:
for whatever in some_iterable:
do_something_with(whatever)
whatever is successively bound to each item in some_iterable. As an example:
>>> mylist = ["A", "B", "C"]
>>> for item in mylist:
... print "item is", item
...
item is A
item is B
item is C
If you want the indexes to, you can use the builtin enumerate(iterable, start=0) function, which yields a (index, item) tuple for each item in iterable:
>>> for index, item in enumerate(mylist):
... print "item %s is %s" % (index, item)
...
item 0 is A
item 1 is B
item 2 is C
You are indexing your lists with a non-int type index:
for count in list_kp2_ok:
for count1 in list_kp2_2_ok:
if list_kp2_ok[count]==list_kp2_2_ok[count1]:
So a quick fix for that is to do it this way:
for coord1 in list_kp2_ok:
for coord2 in list_kp2_2_ok:
if coord1==coord2:
You can even do the whole coding in one statement:
list_wsp=[coords for coords in list_kp2_ok if coords in list_kp2_2_ok]
This will directly output to you the common coordinates in both lists.
You can use list comprehension:
new_list = [i for i in list_kp2_ok if i in list_kp2_2_ok]
You don't have to declare the counter variables. You can iterate through the lists with for-in:
list_wsp = []
for elem in list_k2_ok:
for elem1 in list_k2_2_ok:
if elem == elem1:
list_wsp.append(elem)
This will create the new list with the same coordinates.
An alternative approach might be to try using sets:
for x in set([tuple(l) for l in list_kp2_ok]).intersection(set([tuple(l) for l in list_kp2_2_ok])):
print x
This first converts the inner list items to tuples as they are then hashable by the set function. The answer is then the intersection of the two sets. This would remove any duplicates which may or may not be desirable.

Add two lists in Python

I am trying to add together two lists so the first item of one list is added to the first item of the other list, second to second and so on to form a new list.
Currently I have:
def zipper(a,b):
list = [a[i] + b[i] for i in range(len(a))]
print 'The combined list of a and b is'
print list
a = input("\n\nInsert a list:")
b = input("\n\nInsert another list of equal length:")
zipper(a,b)
Upon entering two lists where one is a list of integers and one a list of strings I get the Type Error 'Can not cocanenate 'str' and 'int' objects.
I have tried converting both lists to strings using:
list = [str(a[i]) + str(b[i]) for i in range(len(a))]
however upon entering:
a = ['a','b','c','d']
b = [1,2,3,4]
I got the output as:
['a1','b2','c3','d4']
instead of what I wanted which was:
['a+1','b+2','c+3','d+4']
Does anyone have any suggestions as to what I am doing wrong?
N.B. I have to write a function that will essentially perform the same as zip(a,b) but I'm not allowed to use zip() anywhere in the function.
Zip first, then add (only not).
['%s+%s' % x for x in zip(a, b)]
What you should do
You should use
list = [str(a[i]) +"+"+ str(b[i]) for i in range(len(a))]
instead of
list = [str(a[i]) + str(b[i]) for i in range(len(a))]
In your version, you never say that you want the plus character in the output between the two elements. This is your error.
Sample output:
>>> a = [1,2,3]
>>> b = ['a','b','c']
>>> list = [str(a[i]) +"+"+ str(b[i]) for i in range(len(a))]
>>> list
['1+a', '2+b', '3+c']

Python wont remove items from list

filtered_list = ['PerezHilton', 'tomCruise', 'q', 'p']
#BIO[user]['follows'] is just a list of strings say ['a', 'b', 'katieh']
#specs is also a string say eg. 'katieh'
for user in filtered_list:
if specs not in BIO[user]['follows']:
filtered_list.remove(user)
The above code for some reson gives this error "ValueError: list.remove(x): x not in list" but clearly 'p' is in the list so why is it not detecting 'p' but it is finding 'q'??
Im soo stumped but any help is appreciated, thanks
** SORRY i FIXED IT NOW *
The list comprehension that does this correctly in one line is at the bottom of the post. Here's some insight into the problem first.
Don't do things like:
for item in list_:
list_.remove(item)
because bad and confusing things happen.
>>> list_ = range(10)
>>> for item in list_:
... list_.remove(item)
...
>>> list_
[1, 3, 5, 7, 9]
Every time you remove an item, you change the indexes for the rest of the items which messes up the loop. One good way to remove items from a list while you're traversing it is to do it by index and work backwards so that removals don't affect the rest of the iterations. This is better because if you remove the 9'th element, then the 8'th element is still the 8'th element but the 10'th element becomes the 9'th element. If you've already dealt with that element, then you don't care what its index is.
>>> list_ = range(10)
>>> for i in xrange(len(list_) - 1, -1, -1):
... del list_[i]
...
>>> list_
[]
Or with a while loop:
i = len(list_)
while i:
i -= 1
del list_[i]
So in your case, the code would look something like
users[:] = [user for user in users if specs in BIO[user]['follows']]
because this is a filtering job and those are best done with list comprehensions. The point of the [:] is that it assigns to a slice of the list instead of clobbering the reference to the list. This means that every other reference to the list will be updated. It's essentially in-place, except that a copy is made before overwriting the original list. For the sake of completeness, here's how to do it with a while loop.
i = len(users)
while i:
i -= 1
if specs not in BIO[users[i]]['follows']:
del users[i]
You could do this if you wanted it done in place. No copy of the list is made here.
Why are you iterating?
>>> un = ['PerezHilton', 'tomCruise', 'q', 'p']
>>> un.remove('p')
>>> un
['PerezHilton', 'tomCruise', 'q']

Categories