List of unique items in a list of tuples - python

I have a list of tuples like this: mylist = [(1,2,3),(6,1,1),(7,8,1),(3,4,5)]. If I use the list comprehension slist = [item for sublist in mylist for item in sublist], I could get slist = [1,2,3,6,1,1,7,8,1,3,4,5].
How should I modify if I need only unique elements in slist like this [1,2,3,6,7,8,4,5]?

Use a set instead of a list.
set(slist)
If you really need it as a list then you can convert it back to a list:
slist = list(set(slist))
Note that this conversion won't preserve the original order of the elements. If you need the same order you can use this instead:
>>> result = []
>>> seen = set()
>>> for innerlist in mylist:
for item in innerlist:
if not item in seen:
seen.add(item)
result.append(item)
>>> result
[1, 2, 3, 6, 7, 8, 4, 5]

You can actually make your first part a bit easier by using itertools.chain.from_iterable and then passing the result to set, which will only retain the unique elements:
>>> mylist = [(1,2,3),(6,1,1),(7,8,1),(3,4,5)]
>>> import itertools
>>> set(itertools.chain.from_iterable(mylist))
set([1, 2, 3, 4, 5, 6, 7, 8])

import itertools
chain = itertools.chain(*mylist)
print(set(chain))
taken from Flattening a shallow list in Python and adapted for use in this question.

You should use python sets http://docs.python.org/library/sets.html
set(yourlist)
it will do the trick

Related

How can I remove all lists from a list in python?

What is the most pythonic way to remove all lists in a list?
For example, if there is a list like this [1,2,['randompie'],3,[],4,5], how can I make it like this [1,2,3,4,5]
Here is what I've tried:
[elem for elem in [1,2,['randompie'],3,[],4,5] if type(elem)!='list']
You can use a list comprehension to easily filter all non-list elements from your list:
>>> l = [1,2,['randompie'],3,[],4,5]
>>> [el for el in l if not isinstance(el, list)]
[1, 2, 3, 4, 5]
Note I used isinstance rather than type. This is for two reasons. The former function is preferred because it takes parent classes into account. And because isinstance allows you to easily extend the list comprehension to filter out other types such as tuples or dicts:
>>> l = [1, 2, ['randompie'], 3, [], 4, 5, (1,)]
>>> [el for el in l if not isinstance(el, (list, tuple))] # filter out tuples and list
[1, 2, 3, 4, 5]
I would use list comprehension:
your_list = [1,2,['randompie'],3,[],4,5]
your_list = [thing for thing in your_list if type(thing) is not list]

Python - How to find an item exists in a list (or sublist)?

For example
my_list = [1, 2, 3, 4, [5, 6], [7, 8]]
I want to find if 7 is in my_list.? The answer should be True, because it is part of the last sublist. Any ideas?
If mylist was a list of only lists you could use itertools.chain.from_iterable()
import itertools
mylist = [[1,2,3,4],[5,6],[7,8]]
merged = list(itertools.chain.from_iterable(mylist))
7 in merged
Since we have a list of ints mixed with lists, we define a custom filter. This could also be done in a single list comprehension, but I can't figure that out right now.
mylist = [1,2,3,4,[5,6],[7,8]]
merged = []
map(lambda l: merged.extend(l) if isinstance(l, list) else merged.append(l), [i for i in mylist])
7 in merged
You could also use the deprecated compiler.ast.flatten function:
from compiler.ast import flatten
merged = flatten(mylist)

How to delete a fixed number of items from end of list in python

If you have a list
myList = [1,2,3,4,5,6,7,8,9,0]
Is there a pythonic way to delete a defined number of items from the end of a list.
EG (pseudocode):
removeFromend(myList, 3)
print myList
>>>[1,2,3,4,5,6,7]
You can use list slicing, which I think is the most pythonic way of doing it:
end_trimm = 3
myList = myList[:-end_trimm]
If you want to mutate the list, setting a slice to an empty list is equivalent to deleting those indices.
myList = [1,2,3,4,5,6,7,8,9,0]
myList[-3:] = []
myList
Out[16]: [1, 2, 3, 4, 5, 6, 7]
This works in cases where you can't simply rebind myList to a new list, e.g. you pass your list to a function and want that function to mutate your list.
deling the slice is the direct approach
>>> myList = [1,2,3,4,5,6,7,8,9,0]
>>> del myList[-3:]
>>> myList
[1, 2, 3, 4, 5, 6, 7]
>>>
The -3 means the slice starts 3 from the end, So the general form is del myList[-n:]

Create a list of integer elements from list of objects

I need to create list of non-duplicated integer elements from list of objects.
For example:
There is an object with two attributes: 'id' and 'other_id':
first = [elem.id for elem in objects_list]
second = [elem.other_id for elem in objects_list]
print first
[0,1,2,3,4,5]
print second
[4,5,6,7,9]
Now I can create two list containing that two attributes from all objects like this:
first = [elem.id for elem in objects_list]
first.extend(elem.other_id for elem in objects_list if elem.other_id not in first)
print first
[0,1,2,3,4,5,6,7,9]
Is there any way to do this in shorter way?
Use a set:
sorted(set().union(first, second)) #returns a sorted list of unique items
Demo:
>>> first = [0,1,2,3,4,5]
>>> second = [4,5,6,7,9]
>>> sorted(set(first + second))
[0, 1, 2, 3, 4, 5, 6, 7, 9]
If the original order matters:
>>> first = [0,1,2,3,4,5]
>>> seen = set(first)
>>> first += [x for x in second if x not in seen and not seen.add(x)]
>>> first
[0, 1, 2, 3, 4, 5, 6, 7, 9]
For large lists the set approach is going to be efficient as sets provide O(1) lookup, for tiny lists your approach is also okay.

python replace list values using a tuple

If I have a list:
my_list = [3,2,2,3,4,1,3,4]
and a tuple
my_tuple = (3,5)
What's the best way of replacing elements in my_list using the tuple:
result = [5,2,2,5,4,1,5,4]
e.g.
for item in my_list:
if(item == my_tuple[0]):
item = my_tuple[1]
More generally, I would have a list of lists, and a list of tuples, and I would like to apply each of the tuples to each of the lists within the list of lists.
The more natural data structure for my_tuple is a dictionary. Consider something like this and use the .get() method:
>>> my_lists = [[3,2,2,3,4,1,3,4], [1,2,3,4,5,6]]
>>> my_tuple_list = [(3,5), (6, 7)]
>>> my_dict = dict(my_tuple_list)
>>> my_dict
{3: 5, 6: 7}
>>> my_lists = [[my_dict.get(x,x) for x in somelist] for somelist in my_lists]
>>> my_lists
[[5, 2, 2, 5, 4, 1, 5, 4], [1, 2, 5, 4, 5, 7]]
Per #Wooble's comment, your code will work if you enumerate.
list_of_lists = [[3,2,2,3,4,1,3,4], [1,3,5,3,4,6,3]]
list_of_tuples = [(3,5), (1,9)]
def tup_replace(mylist, mytuple):
for i, item in enumerate(mylist):
if item == mytuple[0]:
mylist[i] = mytuple[1]
return mylist
then you can just nest that some more to work on a list of list and list of tuples.
for mylist in list_of_lists:
for mytuple in list_of_tuples:
mylist = tup_replace(mylist, mytuple)
print mylist
That said, the dictionary approach is probably better.
Using if item == my_tuple[0], ... in a general case sounds like you are making a switch statement that you want to apply to each item in your list. Use a dictionary instead if you can. (Why isn't there a switch or case statement in python?)
Convert your list of tuples to a lookup dictionary (python's switch statement):
replacements = dict(my_tuples) #thanks to #julio
Then for a single list, reproduce the list with a comprehension, but replace each value with the new value from replacements if it exists:
replaced_list = [replacements.get(original,original) for original in my_list]
I guess there is a more efficient way to do it, but that's for a single list with a list of tuples. You say you also need to do it for a list of lists? Just nest that?
Could you explain more about where you are getting this data and why you need to do it?
If you are trying to replace every 3 in your list with 5, this will do:
[x == my_tuple[0] and my_tuple[1] or x for x in my_list]
If you want to do this, with more than one "translational" tuple, then I really suggest to use a dictionary instead:
trans = {3: 5, 4: 6}
[trans.get(x,x) for x in my_list]
And in the more general case where you have more than one list:
ll = [[3, 2, 3, 4], [5, 4, 3, 4]]
trans = {3: 5, 4: 6}
for i in range(len(ll)):
ll[i] = [trans.get(x,x) for x in ll[i]]
Supposing that you want to replace every old list in ll with the new one.

Categories