Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test all items of a list are disjoint?

Given a list of multiple iterables, I want to test if all items are disjoint.

two sets are said to be disjoint if they have no element in common

Example:

iterables = ["AB", "CDE", "AF"]
all_disjoint(iterables)
# False

iterables = ["AB", "CDE", "FG"]
all_disjoint(iterables)
# True

Python sets have an isdisjoint method which works, but it is designed for testing two elements at a time. One approach is to apply this method to each pairwise group of elements:

import itertools as it


def pairwise_(iterable):
    """s -> (s0,s1), (s1,s2), (s2,s3), ..., (sn,s0)"""
    # Modified: the last element wraps back to the first element.
    a, b = it.tee(iterable, 2)
    first = next(b, None)
    b = it.chain(b, [first])
    return zip(a, b)


def all_disjoint(x):
    return all((set(p0).isdisjoint(set(p1))) for p0, p1 in pairwise_(x))

Here I modified the pairwise itertools recipe to attach the first element one last time. This is not quite right however as it only tests neighboring items rather than each item against all other items in the list. I would like to test all elements more elegantly, with less code. Is there a simpler way to do this?

like image 609
pylang Avatar asked Dec 05 '25 03:12

pylang


2 Answers

IIUC, you can take your list of strings, combine them, and then check if the combined length is equal to the length of the set equivalent of that string or not.

You can use ''.join to join your strings and define your function:

def all_disjoint(iterables):
    total = ''.join(iterables)
    return len(total) == len(set(total))

Now, test:

all_disjoint(['AB', 'CDE', 'AF'])
# False

all_disjoint(['AB', 'CDE', 'FG'])
# True
like image 66
cs95 Avatar answered Dec 07 '25 17:12

cs95


Given what you said about wanting to test that each item is disjoint with all other items, I think this does what you want:

import itertools as it

def all_disjoint(x):
    return all((set(p0).isdisjoint(set(p1))) for p0, p1 in it.combinations(x, 2))

iterables = ['AB', 'CDE', 'AF']
print(all_disjoint(iterables))  # -> False

iterables = ['AB', 'CDE', 'FG']
print(all_disjoint(iterables))  # -> True

# your code gives different answer on this one 
# (because it doesn't check what you want)
iterables = ['AB', 'CDE', 'AH', 'FG']
print(all_disjoint(iterables))  # -> False
like image 29
martineau Avatar answered Dec 07 '25 19:12

martineau