Finding the differences between two nested lists - python

I have a nested list and another nested list which is a subset of the first list:
lst = [[1, 2], [3, 4], [1, 2], [5, 6], [8, 3], [2, 7]]
sublst = [[1, 2], [8, 3]]
How can I find the inner lists which are not in the sublist. The desired output using the above example is:
diff = [[3, 4], [5, 6], [2, 7]]

Use a list comprehension:
In [42]: lst = [[1, 2], [3, 4], [1, 2], [5, 6], [8, 3], [2, 7]]
In [43]: sublst = [[1, 2], [8, 3]]
In [44]: [x for x in lst if x not in sublst]
Out[44]: [[3, 4], [5, 6], [2, 7]]
or filter():
In [45]: filter(lambda x:x not in sublst,lst)
Out[45]: [[3, 4], [5, 6], [2, 7]]

If you convert your lists of lists to lists of tuples then you can create sets from them and use set difference operator:
lst = [[1, 2], [3, 4], [1, 2], [5, 6], [8, 3], [2, 7]]
sublst = [[1, 2], [8, 3]]
def tuples(lst): return [tuple(l) for l in lst]
print set(tuples(lst)) - set(tuples(sublst))
will print:
set([(5, 6), (2, 7), (3, 4)])
For huge lists it may be faster than evaluating [x for x in lst if x not in sublst]

Related

Addition to nested list

I wanted to add element with the next value to the most nested list, i. e.
For list
list_in = [2, 3, [4, 5, [6, 7], 6], 2, [5, 6]]
The program should return
list_out = [2, 3, [4, 5, [6, 7, 8], 6], 2, [5, 6]]
In case with e. x. two equal nests, I wanted to get:
list_in = [2, [4], [3]]
list_out = [2, [4, 5], [3, 4]]
How to do it?
A recursive solution:
list_in = [2, 3, [4, 5, [6, 7], 6], 2, [5, 6]]
def get_depths(lst, depths, current_depth=0):
out = [
get_depths(v, depths, current_depth + 1) if isinstance(v, list) else v
for v in lst
]
depths.setdefault(current_depth, []).append(out)
return out
depths = {}
list_out = get_depths(list_in, depths)
for lst in depths[max(depths)]:
lst.append(lst[-1] + 1)
print(list_out)
Prints:
[2, 3, [4, 5, [6, 7, 8], 6], 2, [5, 6]]
For list_in = [2, [4], [3]] it prints:
[2, [4, 5], [3, 4]]

How can I sort the lists in the list?

I'd like to know how to sort the lists in the list. However, I don't want to align by key. I'd like to change it according to the following method.
arr = [[2, 3], [5, 1], [4, 1], [5, 3], [4, 2]]
# solution...
I_want_arr = [[2, 3], [1, 5], [1, 4], [3, 5], [2, 4]]
i tried it
for i in arr:
i.sort()
but, it didn't work
using list comprehenstion:
arr = [[2, 3], [5, 1], [4, 1], [5, 3], [4, 2]]
sorted_output = [sorted(l) for l in arr]
using map():
sorted_output = list(map(sorted, arr))
#Gabip's solution includes this and a more time efficient one, check that out first!
How about
arr = [[2, 3], [5, 1], [4, 1], [5, 3], [4, 2]]
I_want_arr = [sorted(x) for x in arr]
This outputs
[[2, 3], [1, 5], [1, 4], [3, 5], [2, 4]]

How to get all elements at a specific depth-level in a nested list?

I am looking for a method to get all the elements nested at a user-defined list depth level e.g.:
lst = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
# example 1
level = 1 # user defined level
output = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
# example 2
level = 2
output = [[1, 2], [3, 4], [5, 6], [7, 8]]
# example 3
level = 3
output = [1, 2, 3, 4, 5, 6, 7, 8]
You can just use a recursive algorithm, for example:
output = []
def extract(lists, d):
if d == 1:
return output.extend(lists)
for sub_list in lists:
extract(sub_list, d - 1)
For level 1:
extract(lst, 1)
print(output)
>>> [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
For level 2:
extract(lst, 2)
print(output)
>>> [[1, 2], [3, 4], [5, 6], [7, 8]]
For level 3
extract(lst, 3)
print(output)
>>> [1, 2, 3, 4, 5, 6, 7, 8]
You can use chain.from_iterable to go down one level every time:
from itertools import chain
def get_at_level(lst, level):
for _ in range(level-1):
lst = chain.from_iterable(lst)
return list(lst)
Examples:
>>> lst = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
>>> get_at_level(lst, 1)
[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
>>> get_at_level(lst, 2)
[[1, 2], [3, 4], [5, 6], [7, 8]]
>>> get_at_level(lst, 3)
[1, 2, 3, 4, 5, 6, 7, 8]
Please NOTE, that the function returns only a shallow copy of the original list. So assuming you call with any level that is not the lowest - you will have the same references to sub-lists from the original. This means that modifying the returned list might* change the original! If you don't care about the original list, that's fine. If you don't want it to be changed, create a deep copy of it in the first line of the function.
* Changing the first level of the returned will not be a problem because as explained, list returns a shallow copy. BUT, doing something like get_at_level(lst, 2)[0][0] = 0 will also affect the original.
A recursive function like func as below would work.
It is basically the same as marcos' answer.
func accepts a list as its first argument and depth as the second.
from functools import reduce
lst = [[[1,2],[3,4]],[[5,6],[7,8]]]
func = lambda x, d: x if d == 1 else func(reduce(lambda a,b: a+b, x), d-1)
func(lst, 3) # output [1,2,3,4,5,6,7,8]
This isn't a very clean solution for the problem, but it works!
lst = [[[1,2],[3,4]],[[5,6],[7,8]]]
def function(lst, level):
if level == 1:
print(lst)
elif level == 2:
l2 = []
for x in lst:
for i in x:
l2.append(i)
print(l2)
elif level == 3:
l3 = []
for x in lst:
for i in x:
for a in i:
l3.append(a)
print(l3)
else:
print("Invalid depth level")
function(lst, 1) #level 1, 2 or 3
The problem here is that it isn't dynamic.
You can use a recursive generator function:
def flatten(d, l=1):
for i in d:
yield from ([i] if l == 1 else flatten(i, l-1))
lst = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
print(list(flatten(lst, 3)))
print(list(flatten(lst, 2)))
print(list(flatten(lst, 1)))
Output:
[1, 2, 3, 4, 5, 6, 7, 8]
[[1, 2], [3, 4], [5, 6], [7, 8]]
[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]

extract list pattern from list of list in python

I have a list of the form -
a_list = [[1, [2, 3, 4]], [2, [3, 4]], [3, [4]]]
I want to convert it to the form -
b_list = [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
Using the list comprehension, I have tried with below code
for lst in tup:
for lst1 in tup[1]:
tup2 = [lst[0],lst1]
and getting (which is wrong)-
tup2 = [3, [3, 4]]
Please help, Thanks in advance
Simple to do with a list comprehension:
a_list = [[1, [2, 3, 4]], [2, [3, 4]], [3, [4]]]
b_list = [[x,y] for [x,b] in a_list for y in b]
print(b_list)
result:
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
using [x,b] unpacks the items into x as number and b as your list. Loop through elements of b and build the couples, flat-style.
You could try something like this , no matter how many int are there :
for sub_list in b:
for items in sub_list:
if isinstance(items, list):
track = sub_list.index(items)
first = sub_list[:track]
second = sub_list[track:][0]
import itertools
print([list(k) for k in itertools.product(first, second)])
test case:
b = [[1, [2, 3, 4]], [2, [3, 4]], [3, [4]]]
output:
[[1, 2], [1, 3], [1, 4]]
[[2, 3], [2, 4]]
[[3, 4]]
test case 2:
b=[[1,2,[2, 3, 4]], [2,3,5,6 ,[3, 4]], [3, [4]]]
output:
[[1, 2], [1, 3], [1, 4], [2, 2], [2, 3], [2, 4]]
[[2, 3], [2, 4], [3, 3], [3, 4], [5, 3], [5, 4], [6, 3], [6, 4]]
[[3, 4]]

How do I make each list in the list of lists sort in ascending order?

I have the following lists:
[[1, 5], [3, 7], [4, 2], [7, 8], [6, 3], [2, 5], [4, 1]]
And I am trying to sort them by the first value, after making the list go in ascending order:
Desired output:
[[1, 4], [1, 5], [2, 4], [2, 5], [3, 6], [3, 7], [7, 8]]
However, list.sort() only gives the following:
>>> mylist = [[1, 5], [3, 7], [4, 2], [7, 8], [6, 3], [2, 5], [4, 1]]
>>> mylist.sort()
>>> mylist
[[1, 5], [2, 5], [3, 7], [4, 1], [4, 2], [6, 3], [7, 8]]
>>>
Of course, I could always loop each list in the list of lists and sort it:
>>> mylist
[[1, 5], [2, 5], [3, 7], [4, 1], [4, 2], [6, 3], [7, 8]]
>>> for k in range(len(mylist)):
... mylist[k] = sorted(mylist[k])
...
>>> mylist
[[1, 5], [2, 5], [3, 7], [1, 4], [2, 4], [3, 6], [7, 8]]
>>> sorted(mylist)
[[1, 4], [1, 5], [2, 4], [2, 5], [3, 6], [3, 7], [7, 8]]
But is there a one liner to solve this?
You can do:
sorted(sorted(sublist) for sublist in mylist)
This is a little better than your loop:
for sublist in mylist:
sublist.sort()
mylist.sort()
Of course, this changes each sublist in-place. Judging by your examples, it looks like that is what you want, but I thought I should mention it just in case.
Here is a one liner that does the sort in-place
>>> mylist = [[1, 5], [3, 7], [4, 2], [7, 8], [6, 3], [2, 5], [4, 1]]
>>> mylist.sort(key=lambda x:x.sort() or x)
>>> mylist
[[1, 4], [1, 5], [2, 4], [2, 5], [3, 6], [3, 7], [7, 8]]

Categories

Resources