Python 3.0 - is this true?

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sun Nov 9 01:06:40 EST 2008


On Sat, 08 Nov 2008 20:36:59 -0800, Kay Schluehr wrote:

> On 9 Nov., 05:04, Terry Reedy <tjre... at udel.edu> wrote:
> 
>> Have you written any Python code where you really wanted the old,
>> unpredictable behavior?
> 
> Sure:
> 
> if len(L1) == len(L2):
>     return sorted(L1) == sorted(L2)  # check whether two lists contain
> the same elements
> else:
>     return False
> 
> It doesn't really matter here what the result of the sorts actually is
> as long as the algorithm leads to the same result for all permutations
> on L1 ( and L2 ).

How often do you care about equality ignoring order for lists containing 
arbitrary, heterogeneous types?

In any case, the above doesn't work now, since either L1 or L2 might 
contain complex numbers. The sorted() trick only works because you're 
making an assumption about the kinds of things in the lists. If you want 
to be completely general, the above solution isn't guaranteed to work.

If you're prepared to assume hashability, then the obvious Multiset 
solution is probably better even than the above. If you want complete 
generality, you can't even assume that items in the list can be ordered 
at all, so you need something like this:


def collate_and_sort(L):
    D = {}
    for item in L:
        t = type(item)
        x = D.setdefault(t, [])
        x.append(item)
    for x in D.values():
        try:
            x.sort()
        except TypeError:
            try:
                x.sort(key=str)
            except TypeError:
                x.sort(key=id)
    return D


def unordered_equals(L1, L2):
    if len(L1) != len(L2):
        return False
    try:
        return sorted(L1) == sorted(L2)
    except TypeError:
        return collate_and_sort(L1) == collate_and_sort(L2)


But note that even this solution isn't perfect, since it will fail to do 
the right thing for L1=[1, {}, 2] and L2=[1, {}, 2.0]. Here is a way to 
solve the problem assuming only that the items support equality:

def unordered_equals2(L1, L2):
    if len(L1) != len(L2):
        return False
    for item in L1:
        if L1.count(item) != L2.count(item):
            return False
    return True


-- 
Steven



More information about the Python-list mailing list