5

I need to compare two lists which are basically list-of-list find out the sublists which are present in one list but not other. Also the arrangement of the sublists does not consider i.e. ['a','b'] = ['b,'a']. The two lists are

List_1 = [['T_1','T_2'],['T_2','T_3'],['T_1','T_3']]
List_2 = [['T_1','T_2'],['T_3','T_1']]

The output list should be

out_list = [['T_2','T_3']]
asked Aug 31, 2019 at 10:49
2
  • The answer is already answered. stackoverflow.com/questions/21448310/… Commented Aug 31, 2019 at 10:53
  • your sublists are unique, like no duplicates in your list? Commented Aug 31, 2019 at 11:18

6 Answers 6

4

For two element sublists, this should suffice:

[x for x in List_1 if x not in List_2 and x[::-1] not in List_2]

Code:

List_1 = [['T_1','T_2'],['T_2','T_3'],['T_1','T_3']]
List_2 = [['T_1','T_2'],['T_3','T_1']]
print([x for x in List_1 if x not in List_2 and x[::-1] not in List_2])
answered Aug 31, 2019 at 10:53

4 Comments

That only reliably works for sublists of 2 items, though
@roganjosh, Yes. Already added to my answer. :)
So I see :) I think we can do better, with set intersection but I'll need to flesh it out a bit in my head. This is going to have to scan the lists twice
is this a 2n^2 solution (time complexity)?
3

Here's a little messy functional solution that uses sets and tuples in the process (sets are used because what you're trying to calculate is the symmetric difference, and tuples are used because unlike lists, they're hashable, and can be used as set elements):

List_1 = [['T_1','T_2'],['T_2','T_3'],['T_1','T_3']]
List_2 = [['T_1','T_2'],['T_3','T_1']]
f = lambda l : tuple(sorted(l))
out_list = list(map(list, set(map(f, List_1)).symmetric_difference(map(f, List_2))))
print(out_list)

Output:

[['T_2', 'T_3']]
answered Aug 31, 2019 at 10:55

Comments

3

I'd say frozensets are more appropiate for such task:

fs2 = set(map(frozenset,List_2))
out = set(map(frozenset,List_1)).symmetric_difference(fs2)
print(out) 
# {frozenset({'T_2', 'T_3'})}

The advantage of using frozensets here is that they can be hashed, hence you can simply map both lists and take the set.symmetric_difference.


If you want a nested list from the output, you can simply do:

list(map(list, out))

Note that some sublists might appear in a different order, though given the task should not be a problem

answered Aug 31, 2019 at 10:57

6 Comments

Hmm yeah i think ur right @MrGeek
The issue now is that you don't get a list output, so one way or another, it's gonna look like MrGeek's answer if you follow it through to its entirety
Yes, my whole point here is that using sets or frozensets might simply be more appropiate @roganjosh. So not sure what OP wants to do from here, but depending on the task this might be more useful
Note that if order is interchangeable as it seems, why not use sets @roganjosh but yeah, if the output has to be a nested lists totally agree
Yes yes I know you aren't, just exposing my point of view, agreed :) @roganjosh
|
2

You can convert lists to sets for equality comparison and use any() to add into list only items which doesn't exists in second list:

List_1 = [['T_1', 'T_2'], ['T_2', 'T_3'], ['T_1', 'T_3']]
List_2 = [['T_1', 'T_2'], ['T_3', 'T_1']]
out_list = [l1 for l1 in List_1 if not any(set(l1) == set(l2) for l2 in List_2)]

For better understanding resources consumption and efficiency of each answer I've done some tests. Hope it'll help to choose best.

Results on data from question:

Results on bigger data:

answered Aug 31, 2019 at 11:17

11 Comments

what about testing with 1k-10k-1000k, I'm sure that the top will not be the same, with 3 elements the tests are not so relevant
@rusu_ro1, of course. I've added tests with bigger data.
The timings are interesting but it's not a level playing field. You can see my comments under yatu's answer; it doesn't give back a list.
Also, Austin's answer flat-out is not extensible. I suspect you have learned something from the timing of your own answer, though :)
@roganjosh, I've updated functions to give back same results. And about my answer - It's not a surprise for me. Actually, it's one of reasons why I've added tests, cause my solution looks most compact but definitely not most efficient ;)
|
1

if you do not have duplicates in your lists you can use:

 set(frozenset(e) for e in List_1).symmetric_difference({frozenset(e) for e in List_2})

output:

{frozenset({'T_2', 'T_3'}), frozenset({1, 2})}

if you need a list of lists as output you can use:

[list(o) for o in output]

ouptut:

[['T_2', 'T_3']]
answered Aug 31, 2019 at 11:20

Comments

0

Here is a one-liner variant of the frozenset solutions from @yatu and @rusu_ro1 for those who prefer a more concise syntax:

out = [*map(list,{*map(frozenset,List_1)}^{*map(frozenset,List_2)})]

If it is not required to convert the output into a nested list, just do

out = {*map(frozenset,List_1)}^{*map(frozenset,List_2)}

Meanwhile, one advantage of using the symmetric_difference function rather than the ^ operator is that the former can take any iterable as its argument. This avoids converting map(frozenset,List_2) into a set and therefore gains some performance.

out = [*map(list,{*map(frozenset,List_1)}.symmetric_difference(map(frozenset,List_2)))]
answered Aug 31, 2019 at 14:18

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.