Get single elements of list of list of list [duplicate] - python

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Flatten (an irregular) list of lists in Python
I have a list in python like
l=[1,2,[3,4,5],[[4,2,4],[4,7,8]]]
I want using a set to get all unique values, but this fails
set(l)
TypeError: unhashable type: 'list'
So anybody help please? Want to use set with list of list of list etc etc THX

You'll need to 'unwind', or flatten the nested structure before you can put this in a set. You can use a generator for that to keep this efficient for large lists:
def flatten(lst):
for element in lst:
if isinstance(element, list):
for subelement in flatten(element):
yield subelement
else:
yield element
then use that generator on your list l to create a set:
set(flatten(l))

How about this approach, you flatten the list first before you apply the set operation on it.
import collections
def flat_list(tlist):
if isinstance(tlist, collections.Iterable):
return [j for i in tlist for j in flat_list(i)]
else:
return [tlist]
then:
myl=[1,2,[3,4,5],[[4,2,4],[4,7,8]]]
print set(flat_list(myl))
gives:
set([1, 2, 3, 4, 5, 7, 8])
#MartijnPieters approach with a generator will work more efficiently with very large lists than this list comprehension based approach.

Related

List index out of range in loop [duplicate]

This question already has answers here:
python : list index out of range error while iteratively popping elements
(12 answers)
Closed 2 years ago.
Im getting an error for list index being out of range. Sorry if this is a stupid question.
def filter_list(l):
for x in range(0, len(l)):
if type(l[x]) is str:
del l[x]
return l
When you use del to delete the item in the list, the list actually shortens and it seems like that is what is causing the problem.
If you would like to filter lists, you could use list comprehensions like so:
def filter(l):
return [item for item in l if type(item) is not str]
Usually, when looping over lists, it is good practice not to delete or insert new items.
Hope this helped
You should not definitely change a list while iterating over it. It is very bad practise... it can lead to a whole lot of errors for you. Either you should create a copy of use something else, as list comprehension:
def filter_list(l):
return [x for x in l if type(x) is not str]
print(filter_list([1, 4, 5, 's', 'demo'])) # Prints [1, 4, 5]

Merge two lists if an element is a duplicate (python) [duplicate]

This question already has answers here:
Merge lists that share common elements
(15 answers)
Closed 7 years ago.
I have a list of lists and am wanting to merge together all lists if any element of a list is in both lists.
For example, consider this list of lists:
[[0],[1,2,3,4],[4,5,6],[6,7,8]]
The output should be:
[0],[1,2,3,4,5,6,7,8]
Try the following. Tested in python3.
def mergeOrNot(list1,list2):
merge=False
for item in list1:
if item in list2:
merge=True
break
return merge
def uniqueList(list1,list2):
result = set()
for item in list1:
result.add(item)
for item in list2:
result.add(item)
return result
def cleverMergeLists(lists):
anotherLoopRequired=False
newList = []
for myList in lists:
addMyList=True
if not anotherLoopRequired:
for myList2 in lists:
if not anotherLoopRequired:
if(myList==myList2):
continue
if(mergeOrNot(myList,myList2)):
anotherLoopRequired=True
addMyList=False
newList.append(uniqueList(myList,myList2))
else:
newList.append(myList2)
if(addMyList):
newList.append(myList)
if anotherLoopRequired:
return cleverMergeLists(newList)
else:
return newList
print(cleverMergeLists([[0],[1,2,3,4],[4,5,6],[6,7,8]]))
Outputs the following:
[0], {1, 2, 3, 4, 5, 6, 7, 8}]
Can't vouch for efficiency or anything, and I've only tested it on your list, so may contain bugs or not work for some cases.
The cleverMergeLists function loops over items in the list, and works out if two items need merging. If they do, it calls itself on a new list with two of the items merged, if not, it returns the list as was passed to it.

How does the list comprehension to flatten a python list work? [duplicate]

This question already has answers here:
How can I use list comprehensions to process a nested list?
(13 answers)
Closed 7 months ago.
I recently looked for a way to flatten a nested python list, like this: [[1,2,3],[4,5,6]], into this: [1,2,3,4,5,6].
Stackoverflow was helpful as ever and I found a post with this ingenious list comprehension:
l = [[1,2,3],[4,5,6]]
flattened_l = [item for sublist in l for item in sublist]
I thought I understood how list comprehensions work, but apparently I haven't got the faintest idea. What puzzles me most is that besides the comprehension above, this also runs (although it doesn't give the same result):
exactly_the_same_as_l = [item for item in sublist for sublist in l]
Can someone explain how python interprets these things? Based on the second comprension, I would expect that python interprets it back to front, but apparently that is not always the case. If it were, the first comprehension should throw an error, because 'sublist' does not exist. My mind is completely warped, help!
Let's take a look at your list comprehension then, but first let's start with list comprehension at it's easiest.
l = [1,2,3,4,5]
print [x for x in l] # prints [1, 2, 3, 4, 5]
You can look at this the same as a for loop structured like so:
for x in l:
print x
Now let's look at another one:
l = [1,2,3,4,5]
a = [x for x in l if x % 2 == 0]
print a # prints [2,4]
That is the exact same as this:
a = []
l = [1,2,3,4,5]
for x in l:
if x % 2 == 0:
a.append(x)
print a # prints [2,4]
Now let's take a look at the examples you provided.
l = [[1,2,3],[4,5,6]]
flattened_l = [item for sublist in l for item in sublist]
print flattened_l # prints [1,2,3,4,5,6]
For list comprehension start at the farthest to the left for loop and work your way in. The variable, item, in this case, is what will be added. It will produce this equivalent:
l = [[1,2,3],[4,5,6]]
flattened_l = []
for sublist in l:
for item in sublist:
flattened_l.append(item)
Now for the last one
exactly_the_same_as_l = [item for item in sublist for sublist in l]
Using the same knowledge we can create a for loop and see how it would behave:
for item in sublist:
for sublist in l:
exactly_the_same_as_l.append(item)
Now the only reason the above one works is because when flattened_l was created, it also created sublist. It is a scoping reason to why that did not throw an error. If you ran that without defining the flattened_l first, you would get a NameError
The for loops are evaluated from left to right. Any list comprehension can be re-written as a for loop, as follows:
l = [[1,2,3],[4,5,6]]
flattened_l = []
for sublist in l:
for item in sublist:
flattened_l.append(item)
The above is the correct code for flattening a list, whether you choose to write it concisely as a list comprehension, or in this extended version.
The second list comprehension you wrote will raise a NameError, as 'sublist' has not yet been defined. You can see this by writing the list comprehension as a for loop:
l = [[1,2,3],[4,5,6]]
flattened_l = []
for item in sublist:
for sublist in l:
flattened_l.append(item)
The only reason you didn't see the error when you ran your code was because you had previously defined sublist when implementing your first list comprehension.
For more information, you may want to check out Guido's tutorial on list comprehensions.
For the lazy dev that wants a quick answer:
>>> a = [[1,2], [3,4]]
>>> [i for g in a for i in g]
[1, 2, 3, 4]
While this approach definitely works for flattening lists, I wouldn't recommend it unless your sublists are known to be very small (1 or 2 elements each).
I've done a bit of profiling with timeit and found that this takes roughly 2-3 times longer than using a single loop and calling extend…
def flatten(l):
flattened = []
for sublist in l:
flattened.extend(sublist)
return flattened
While it's not as pretty, the speedup is significant. I suppose this works so well because extend can more efficiently copy the whole sublist at once instead of copying each element, one at a time. I would recommend using extend if you know your sublists are medium-to-large in size. The larger the sublist, the bigger the speedup.
One final caveat: obviously, this only holds true if you need to eagerly form this flattened list. Perhaps you'll be sorting it later, for example. If you're ultimately going to just loop through the list as-is, this will not be any better than using the nested loops approach outlined by others. But for that use case, you want to return a generator instead of a list for the added benefit of laziness…
def flatten(l):
return (item for sublist in l for item in sublist) # note the parens
Note, of course, that the sort of comprehension will only "flatten" a list of lists (or list of other iterables). Also if you pass it a list of strings you'll "flatten" it into a list of characters.
To generalize this in a meaningful way you first want to be able to cleanly distinguish between strings (or bytearrays) and other types of sequences (or other Iterables). So let's start with a simple function:
import collections
def non_str_seq(p):
'''p is putatively a sequence and not a string nor bytearray'''
return isinstance(p, collections.Iterable) and not (isinstance(p, str) or isinstance(p, bytearray))
Using that we can then build a recursive function to flatten any
def flatten(s):
'''Recursively flatten any sequence of objects
'''
results = list()
if non_str_seq(s):
for each in s:
results.extend(flatten(each))
else:
results.append(s)
return results
There are probably more elegant ways to do this. But this works for all the Python built-in types that I know of. Simple objects (numbers, strings, instances of None, True, False are all returned wrapped in list. Dictionaries are returned as lists of keys (in hash order).

Converting matrix to an array in python [duplicate]

This question already has answers here:
How do I make a flat list out of a list of lists?
(34 answers)
Closed 10 years ago.
I have an array of array in python. What is the best way to convert it to an array in python?
for example:
m = [[1,2],[3,4]]
# convert to [1,2,3,4]
I am new in python, so I dont know any solution of it better than writing a loop. Please help.
Use itertools.chain or list comprehension:
from itertools import chain
list(chain(*m)) # shortest
# or:
list(chain.from_iterable(m)) # more efficient
For smaller lists comprehension is faster, for longer ones chain.from_iterable is more suitable.
[item for subl in m for item in subl]
For understanding the nested comprehension, you can split it across multiple lines and compare it to a regular for loop:
[item #result = []
for subl in m #for subl in m:
for item in subl] # for item in subl:
# result.append(item)

getting all elements of a python list ,including sublists [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Flatten (an irregular) list of lists in Python
I have a python list whose elements can be letters or lists of letters.I wanted to write a function to extract all elements as below
suppose
l=['a',['b',['c']] ]
The output need to be ['a','b','c']
I thought recursion would be the correct way to do this.
The base case may be that the list contains only one element.
I tried to code this..but the output is
['a', 'b', ['c']]
Can someone please tell me what went wrong here?
def get_all_elements(mylist):
if len(mylist)==1:
return mylist[0]
else:
output=[mylist[0]]
output+=get_all_elements(mylist[1:])
return output
This seems to work Ok:
def flatten(iterable):
out = []
for i in iterable:
if hasattr(i,'__iter__'):
out.extend(flatten(i))
else:
out.append(i)
return out
l=['a',['b',['c']] ]
print flatten(l)
Where you went wrong is that in your solution, mylist[0] can itself be a list (of length 1) which contains another list (of arbitrary length). In that case, you just returned it.
When you check to see if mylist is of length 1, you don't check for the case where its contents are a list. Here's an example that will highlight your problem.
get_all_elements([1, [2, [3, 4]]])
If you want a complete solution, Flattening a shallow list in Python and Comprehension for flattening a sequence of sequences? are good places to look.
this will work on up to 3 levels deep, if the depth is arbitrary i don't think you'll be able to use a list comprehension.
[grandchild for parent in l for child in parent for grandchild in child]

Categories

Resources