Unable to sort multilist in python - python

I tried to sort list within a list but failed to do so , Is something wrong with my code ?
x = [[int(i)] for i in raw_input().split()]
print x
q = x.sort(key=lambda p: p[0])
print q
Before this I tried simpler code such as:
x = [[int(i)] for i in raw_input().split()]
print (x.sort())
But the result is same in both cases :

list.sort is an in-place operation that returns None. So you're assigning None.
If you want a new list to be returned as a value use sorted:
q = sorted(x, key=...)
print(q)
If you want to mutate the x in place use:
x.sort(...)
print(x)
Tip - to get a flat list use:
from itertools import chain
q = list(chain.from_iterable(x))
And now if you want to sort:
q = sorted(q) # no need for key

Related

Converting tuple to list

I am trying to convert this tuple into a list, however when I run this code:
mytuple=('7578',), ('6052',), ('8976',), ('9946',)
List=[]
for i in mytuple:
Start,Mid,End = map(str, mytuple.split("'"))
List.append(Mid)
print(List)
I receive this error:
AttributeError: 'tuple' object has no attribute 'split'
The output should be:
[7578, 6052, 8976, 9946]
this is what you are looking for
mytuple = (('7578',), ('6052',), ('8976',), ('9946',))
result = [int(x) for x, in mytuple]
print(result)
If I understood correctly, this is want you want:
mytuple = ('7578',), ('6052',), ('8976',), ('9946',)
result = [e for e, in mytuple]
print(result)
Output
['7578', '6052', '8976', '9946']
I would use itertools.chain.from_iterable (which errs on the side of too much verbosity than too little):
from itertools import chain
result = [int(x) for x in chain.from_iterable(mytuple)]
# vs ... for x, in mytuple]; the comma is easy to miss
Somewhere between the two extremes would be
result = [int(x) for x in chain(*mytuple)]

Lists comparison in loop: print second tuple element if condition

I have the following list and nested list:
first_var = ["id1","id2","id3"]
second_var = [("id1","name1"),("id2","name2"),("id3","name3"),("id4","name4"),]
I want to check for each first element in 'second_var' that doesn't exist in 'first_var' and print the second element in the 'second_var'.
my code is:
for x in [x[0] for x in second_var]:
if x not in first_var:
print(...)
For now if i execute print(x) it prints:
id4
but i need it to print
name4
How can i achieve that?
The problem with your code is you are not iterating the original list. You are only iterating the first entry of each tuple within the list.
This is how you can adapt your code:
first_var = ["id1","id2","id3"]
second_var = [("id1","name1"),("id2","name2"),("id3","name3"),("id4","name4"),]
for x in second_var:
if x[0] not in first_var:
print(x[1])
The Pythonic solution is to convert this to a list comprehension:
values = set(first_var)
res = [x[1] for x in second_var if x[0] not in values]
for item in res:
print(item)
Or the functional version; not recommended, but another way of seeing the logic:
from operator import itemgetter
values = set(first_var)
res = map(itemgetter(1), filter(lambda x: x[0] not in values, second_var))
>>> [v[1] for v in second_var if v[0] not in first_var]
['name4']
You can use list comprehension feature.
ids = [tuple[1] for tuple in second_var if tuple[0] not in first_var]
print(ids)
Output
['name4']
The list comprehension statement above is equivalent to:
>>> result = []
for tuple in second_var:
if tuple[0] not in first_var:
result.append(tuple[1])
>>> result
['name4']
If you have a lot of data, you need to build a dictionary & use set & all those nice hashing/difference techniques already existing in Python instead of linear lookup in lists (O(1) vs O(n)).
first_var = ["id1","id2","id3"]
second_var = [("id1","name1"),("id2","name2"),("id3","name3"),("id4","name4"),]
second_d = dict(second_var) # create a dict directly from tuples
missing = set(second_d).difference(first_var)
for m in missing:
print(second_d[m])
this prints name4
missing is the difference between the dict keys and the list.

Distinct List of Lists With Set

I created a list of lists and then tried to get a distinct list of the lists using set(), but it appears as though i cant use list on a set.
Is there another way to accomplish this with a concise statement that performs well?
CODE
x = [1,2]
y = [1,2]
z = [2,3]
xyz = []
xyz.append(x)
xyz.append(y)
xyz.append(z)
set(xyz)
Error
TypeError: unhashable type: 'list'
Goal
xyz = [[1,2],[2,3]]
if you want to preserve order and keep your lists, you could use generator function to remove the dupes from your list:
xyz = [x, y, z]
def remove_dupe_subs(l):
seen = set()
for sub in l:
tup = tuple(sub)
if tup not in seen:
yield sub
seen.add(tup)
xyz[:] = remove_dupe_subs(xyz)
Or using a generator expression taking advantage of the fact set.add returns None :
seen = set()
xyz[:] = (seen.add(tup) or sub for sub, tup in zip(xyz, map(tuple, xyz)) if tup not in seen)
print(xyz)
If the list members are hashable, it will work
x = [1,2]
y = [1,2]
z = [2,3]
xyz = []
xyz.append(tuple(x))
xyz.append(tuple(y))
xyz.append(tuple(z))
print xyz
xyz_set = set(xyz)
print xyz_set
It's a little bit convoluted, but this will do the trick in a single line:
xyz=[list(x) for x in list(set((tuple(x),tuple(y),tuple(z))))]

Dropping values from a list of tuples

I have a list of tuples which I would like to only return the second column of data from and only unique values
mytuple = [('Andrew','Andrew#gmail.com','20'),('Jim',"Jim#gmail.com",'12'),("Sarah","Sarah#gmail.com",'43'),("Jim","Jim#gmail.com",'15'),("Andrew","Andrew#gmail.com",'56')]
Desired output:
['Andrew#gmail.com','Jim#gmail.com','Sarah#gmail.com']
My idea would be to iterate through the list and append the item from the second column into a new list then use the following code. Before I go down that path too far I know there is a better way to do this.
from collections import Counter
cnt = Counter(mytuple_new)
unique_mytuple_new = [k for k, v in cnt.iteritems() if v > 1]
You can use zip function :
>>> set(zip(*mytuple)[1])
set(['Sarah#gmail.com', 'Jim#gmail.com', 'Andrew#gmail.com'])
Or as a less performance way you can use map and operator.itemgetter and use set to get the unique tuple :
>>> from operator import itemgetter
>>> tuple(set(map(lambda x:itemgetter(1)(x),mytuple)))
('Sarah#gmail.com', 'Jim#gmail.com', 'Andrew#gmail.com')
a benchmarking on some answers :
my answer :
s = """\
mytuple = [('Andrew','Andrew#gmail.com','20'),('Jim',"Jim#gmail.com",'12'),("Sarah","Sarah#gmail.com",'43'),("Jim","Jim#gmail.com",'15'),("Andrew","Andrew#gmail.com",'56')]
set(zip(*mytuple)[1])
"""
print timeit.timeit(stmt=s, number=100000)
0.0740020275116
icodez answer :
s = """\
mytuple = [('Andrew','Andrew#gmail.com','20'),('Jim',"Jim#gmail.com",'12'),("Sarah","Sarah#gmail.com",'43'),("Jim","Jim#gmail.com",'15'),("Andrew","Andrew#gmail.com",'56')]
seen = set()
[x[1] for x in mytuple if x[1] not in seen and not seen.add(x[1])]
"""
print timeit.timeit(stmt=s, number=100000)
0.0938332080841
Hasan's answer :
s = """\
mytuple = [('Andrew','Andrew#gmail.com','20'),('Jim',"Jim#gmail.com",'12'),("Sarah","Sarah#gmail.com",'43'),("Jim","Jim#gmail.com",'15'),("Andrew","Andrew#gmail.com",'56')]
set([k[1] for k in mytuple])
"""
print timeit.timeit(stmt=s, number=100000)
0.0699651241302
Adem's answer :
s = """
from itertools import izip
mytuple = [('Andrew','Andrew#gmail.com','20'),('Jim',"Jim#gmail.com",'12'),("Sarah","Sarah#gmail.com",'43'),("Jim","Jim#gmail.com",'15'),("Andrew","Andrew#gmail.com",'56')]
set(map(lambda x: x[1], mytuple))
"""
print timeit.timeit(stmt=s, number=100000)
0.237300872803 !!!
unique_emails = set(item[1] for item in mytuple)
The list comprehension will help you generate a list containing only the second column data, and converting that list to set() removes duplicated values.
try:
>>> unique_mytuple_new = set([k[1] for k in mytuple])
>>> unique_mytuple_new
set(['Sarah#gmail.com', 'Jim#gmail.com', 'Andrew#gmail.com'])
You can use a list comprehension and a set to keep track of seen values:
>>> mytuple = [('Andrew','Andrew#gmail.com','20'),('Jim',"Jim#gmail.com",'12'),("Sarah","Sarah#gmail.com",'43'),("Jim","Jim#gmail.com",'15'),("Andrew","Andrew#gmail.com",'56')]
>>> seen = set()
>>> [x[1] for x in mytuple if x[1] not in seen and not seen.add(x[1])]
['Andrew#gmail.com', 'Jim#gmail.com', 'Sarah#gmail.com']
>>>
The most important part of this solution is that order is preserved like in your example. Doing just set(x[1] for x in mytuple) or something similar will get you the unique items, but their order will be lost.
Also, the if x[1] not in seen and not seen.add(x[1]) may seem a little strange, but it is actually a neat trick that allows you to add items to the set inside the list comprehension (otherwise, we would need to use a for-loop).
Because and performs short-circuit evaluation in Python, not seen.add(x[1]) will only be evaluated if x[1] not in seen returns True. So, the condition sees if x[1] is in the set and adds it if not.
The not operator is placed before seen.add(x[1]) so that the condition evaluates to True if x[1] needed to be added to the set (set.add returns None, which is treated as False. not False is True).
How about the obvious and simple loop? There is no need to create a list and then convert to set, just don't add dupliates.
mytuple = [('Andrew','Andrew#gmail.com','20'),('Jim',"Jim#gmail.com",'12'),("Sarah","Sarah#gmail.com",'43'),("Jim","Jim#gmail.com",'15'),("Andrew","Andrew#gmail.com",'56')]
result = []
for item in mytuple:
if item[1] not in result:
result.append(item[1])
print result
Output:
['Andrew#gmail.com', 'Jim#gmail.com', 'Sarah#gmail.com']
Is the order of the items important? A lot of the proposed answers use set to unique-ify the list. That's good, proper, and performant if the order is unimportant. If order does matter, you can used an OrderedDict to perform set-like unique-ification while preserving order.
# test data
mytuple = [('Andrew','Andrew#gmail.com','20'),('Jim',"Jim#gmail.com",'12'),("Sarah","Sarah#gmail.com",'43'),("Jim","Jim#gmail.com",'15'),("Andrew","Andrew#gmail.com",'56')]
from collections import OrderedDict
emails = list(OrderedDict((t[1], 1) for t in mytuple).keys())
print emails
Yielding:
['Andrew#gmail.com', 'Jim#gmail.com', 'Sarah#gmail.com']
Update
Based on iCodez's suggestion, restating answer to:
from collections import OrderedDict
emails = list(OrderedDict.fromkeys(t[1] for t in mytuple).keys())

Test for list membership and get index at the same time in Python

It seems silly to write the following:
L = []
if x in L:
L[x] = something
else:
L[x] = something_else
Doesn't this perform the look-up for x twice? I tried using index(), but this gives an error when the value is not found.
Ideally I would like to say like:
if x is in L, save that index and:
...
I can appreciate that this might be a beginner python idiom, but it seems rather un-search-able. Thanks.
Another option is try/except:
d = {}
try:
d[x] = something_else
except KeyError:
d[x] = something
Same result as your code.
Edit: Okay, fast moving target. Same idiom for a list, different exception (IndexError).
Do you mean you want setdefault(key[, default])
a = {}
a['foo'] # KeyError
a.setdefault('foo', 'bar') # key not exist, set a['foo'] = 'bar'
a.setdefault('foo', 'x') # key exist, return 'bar'
If you have a list you can use index, catching the ValueError if it is thrown:
yourList = []
try:
i = yourList.index(x)
except ValueError:
i = None
Then you can test the value of i:
if i is not None:
# Do things if the item was found.
I think your question confused many because you've mixed your syntax between dict and list.
If:
L = [] # L is synonym for list and [] (braces) used to create list()
Here you are looking for a value in a list, not a key nor a value in a dict:
if x in L:
And then you use x seemingly intended as a key but in lists it's an int() index and doing if x in L: doesn't test to see if index is in L but if value is in L:
L[x]=value
So if you intend to see if a value is in L a list do:
L = [] # that's a list and empty; and x will NEVER be in an empty list.
if x in L: # that looks for value in list; not index in list
# to test for an index in a list do if len(L)>=x
idx = L.index(x)
L[idx] = something # that makes L[index]=value not L[key]=value
else:
# x is not in L so you either append it or append something_else
L.append(x)
If you use:
L[x] = something together with if x in L: then it would make sense to have a list with only these values: L=[ 0, 1, 2, 3, 4, ...] OR L=[ 1.0, 2.0, 3.0, ...]
But I'd offer this:
L = []
L.extend(my_iterable)
coder0 = 'farr'
coder1 = 'Mark Byers'
if coder0 not in L:
L.append(coder1)
Weird logic

Categories