Intersection of two nested lists in Python - list

I've a problem with the nested lists. I want to compute the lenght of the intersection of two nested lists with the python language. My lists are composed as follows:
list1 = [[1,2], [2,3], [3,4]]
list2 = [[1,2], [6,7], [4,5]]
output_list = [[1,2]]
How can i compute the intersection of the two lists?

I think there are two reasonable approaches to solving this issue.
If you don't have very many items in your top level lists, you can simply check if each sub-list in one of them is present in the other:
intersection = [inner_list for inner in list1 if inner_list in list2]
The in operator will test for equality, so different list objects with the same contents be found as expected. This is not very efficient however, since a list membership test has to iterate over all of the sublists. In other words, its performance is O(len(list1)*len(list2)). If your lists are long however, it may take more time than you want it to.
A more asymptotically efficient alternative approach is to convert the inner lists to tuples and turn the top level lists into sets. You don't actually need to write any loops yourself for this, as map and the set type's & operator will take care of it all for you:
intersection_set = set(map(tuple, list1)) & set(map(tuple, list2))
If you need your result to be a list of lists, you can of course, convert the set of tuples back into a list of lists:
intersection_list = list(map(list, intersection_set))

What about using sets in python?
>>> set1={(1,2),(2,3),(3,4)}
>>> set2={(1,2),(6,7),(4,5)}
>>> set1 & set2
set([(1, 2)])
>>> len(set1 & set2)
1

import json
list1 = [[1,2], [2,3], [3,4]]
list2 = [[1,2], [6,7], [4,5]]
list1_str = map(json.dumps, list1)
list2_str = map(json.dumps, list2)
output_set_str = set(list1_str) & set(list2_str)
output_list = map(json.loads, output_set_str)
print output_list

Related

How can I calculate the sums of all possible combinations of elements of a set? [Python]

For example, I have the list L = [1,2,4]. For the sake of comprehension, I want to list all the combinations for two pulls with a put back (the order does not matter):
[1,1]
[1,2]
[2,2]
[1,4]
[2,4]
The sum of the respective lists is then: [2,3,4,5,6].
So I want to get the output [2,3,4,5,6] from the input [1,2,4] with a function, so to speak. In the general case, the list has k elements and N elements are taken for the combinations. Say:
def fun(L,N):
...
(do the thing)
return sum_list
something like below
L = [1, 2, 4]
k = []
for i in range(len(L)):
for j in range(len(L)-i):
k.append(L[j+i] + L[i])

How do I bag elements of tuples in Prolog lists

Say I have a list:
Os = [(4,P1),(9,P2),(4,P3),(1,P4),(9,P5)].
I want to put every second element of the tuple in a bag that has the same first element like this:
SortedOs = [(4,[P1,P3]),(9,[P2,P5]),(1,P4)].
Currently I'm using bagof/3:
findall(
(O,Bag),
bagof(P,member((O,P),Os),Bag),
SortedOs
).
But instead it gives me the sorted list like this:
SortedOs = [(1,P4),(4,[P1,P3]),(9,[P2,P5])]
Which means bagof/3 looks up the first element in ascending order. Is there any way I can change this to get the list I want? Many thanks.
If you are using SWI-Prolog and you can change the format of the data from tuples to Pairs, (Key-Value) then you can use group_pairs_by_key/2.
Note that for group_pairs_by_key/2 to work correctly the input list must be sorted.
Code
example(Pairs0,Result) :-
sort(Pairs0,Pairs1),
group_pairs_by_key(Pairs1,Result).
Example usage
?- Pairs = [4-P1,9-P2,4-P3,1-P4,9-P5],example(Pairs,Result).
Pairs = [4-P1, 9-P2, 4-P3, 1-P4, 9-P5],
Result = [1-[P4], 4-[P1, P3], 9-[P2, P5]].
SWI-Prolog has a library of predicates for working with ordered sets (sorted list). ordsets.pl -- Ordered set manipulation
Here is a variation that checks if the input is an ordered set and skips the sorting if it is an ordered set.
example(List,Result) :-
(
is_ordset(List)
->
Order_set = List
;
list_to_ord_set(List,Order_set)
),
group_pairs_by_key(Order_set,Result).
Example usage
?- List = [1-P4, 4-P1, 4-P3, 9-P2, 9-P5],example(List,Result).
List = [1-P4, 4-P1, 4-P3, 9-P2, 9-P5],
Result = [1-[P4], 4-[P1, P3], 9-[P2, P5]].
?- List = [4-P1,9-P2,4-P3,1-P4,9-P5],example(List,Result).
List = [4-P1, 9-P2, 4-P3, 1-P4, 9-P5],
Result = [1-[P4], 4-[P1, P3], 9-[P2, P5]].
Note: Ordered Sets remove duplicates so using list_to_ord_set/2 instead of sort/2 will remove duplicates.
?- List = [4-P1,4-P1,9-P2,4-P3,1-P4,9-P5],example(List,Result).
List = [4-P1, 4-P1, 9-P2, 4-P3, 1-P4, 9-P5],
Result = [1-[P4], 4-[P1, P3], 9-[P2, P5]].
group_pairs_by_key/2 (source code)

Why do I get extra element when getting every other element in a list?

I'm new to haskell and I dont know why I'm getting an extra element in a list.
Here's my code:
module Test where
deal list = hand1
where list' = fst(splitAt 4 list)
hand1 = [snd list' | list'<- (zip [0..] list), even (fst list')]
If I were to put in:
Test.deal [1,2,3,4,5,6]
It splits the list to create to create a tuple of two lists one with length of 4: ([1,2,3,4],[5,6])
When I try to get every other element of the first list in the tuple, I get: [1,3,5] instead of [1,3]
Anyone know why it adds the 5 even though it isn't in the list?
You are defining two different list'. The one inside the list comprehension list'<- (zip [0..] list) shadows the previous one. Shadowing means you have two equal names in scope but the one lexically closer is the only one visible. You want something like:
module Test where
deal list = hand1
where list0 = fst (splitAt 4 list)
hand1 = [snd list1 | list1 <- (zip [0..] list0), even (fst list1)]
With these changes, I can do
λ> deal [1,2,3,4,5,6]
[1,3]

python 3, comparing elements of two lists of lists

I'm trying to compare elements of 2 lists of lists in python. I want to create a new list (ph) which has a 1 if elements of lists from the 1st list of lists are in the elements of the 2nd list of lists.
However, this seems to compare the whole list and not individual elements. The code is below. Many thanks for the help! :)
import numpy as np
import pandas as pd
abc = [[1,800000,3],[4,5,6],[100000,7,8]]
l = [[
[i for i in range(0, 100000)],
[i for i in range(200000,300000)],
[i for i in range(400000,500000)],
[i for i in range(600000,700000)],
[i for i in range(800000,900000)],
[i for i in range(1000000,1100000)]
]]
ph = []
for i in abc:
for j in l:
if l[0] == abc[0]:
ph.append(1)
else:
ph.append(0)
print(ph)
The goal of your problem is somewhat unclear to me. Correct me if I'm wrong but what you want is: for each sublist of abc, get a boolean describing if all its elements are anywhere in l. Is that it ?
If it is indeed the case, here's my answer.
First of all, your second list is not a list of lists but a list of lists of lists. Hence, I removed a nested list in my code.
abc = [[1,800000,3],[4,5,6],[100000,7,8]]
L = [
[i for i in range(0, 100000)],
[i for i in range(200000,300000)],
[i for i in range(400000,500000)],
[i for i in range(600000,700000)],
[i for i in range(800000,900000)],
[i for i in range(1000000,1100000)]
]
flattened_L = sum(L, [])
print(
list(map(lambda sublist: all(x in flattened_L for x in sublist), abc))
)
# returns [True, True, False]
My code first flattens L so that is becomes easy to check whether any element is in it or not. Then, for each sublist in abc, it checks if all elements are in this flattened list.
Note: my code returns a list of boolean. If you absolutely need integers value (0 and 1), which you shouldn't, you can wrap int around all.

Unique elements inside lists of list

If I have a nested list like:
l = [['AB','BCD','TGH'], ['UTY','AB','WEQ'],['XZY','LIY']]
In this example, 'AB' is common to the first two nested lists. How can I remove 'AB' in both lists while keeping the other elements as is? In general how can I remove a element from every nested list that occurs in two or more nested lists so that each nested list is unique?
l = [['BCD','TGH'],['UTY','WEQ'],['XZY','LIY']]
Is it possible to do this with a for loop?
Thanks
from collections import Counter
from itertools import chain
counts = Counter(chain(*ls)) # find counts
result = [[e for e in l if counts[e] == 1] for l in ls] # take uniqs
One option is to do something like this:
from collections import Counter
counts = Counter([b for a in l for b in a])
for a in l:
for b in a:
if counts[b] > 1:
a.remove(b)
Edit: If you want to avoid the (awfully useful standard library) collections module (cf. the comment), you could replace counts above by the following custom counter:
counts = {}
for a in l:
for b in a:
if b in counts:
counts[b] += 1
else:
counts[b] = 1
A somewhat short solution without imports would be to create a reduced version of the original list first, then iterate through the original list and remove elements with counts greater than 1:
lst = lst = [['AB','BCD','TGH'], ['UTY','AB','WEQ'],['XZY','LIY']]
reduced_lst = [y for x in lst for y in x]
output_lst = []
for chunk in lst:
chunk_copy = chunk[:]
for elm in chunk:
if reduced_lst.count(elm)>1:
chunk_copy.remove(elm)
output_lst.append(chunk_copy)
print(output_lst)
Should print:
[['BCD', 'TGH'], ['UTY', 'WEQ'], ['XZY', 'LIY']]
I hope this proves useful.