简体   繁体   中英

Given an arbitrary collection, is there a way to tell if it is ordered?

Here's what I have so far:

def is_ordered(collection):
    if isinstance(collection, set):
        return False
    if isinstance(collection, list):
        return True
    if isinstance(collection, dict):
        return False

    raise Exception("unknown collection")

Is there a much better way to do this?

NB: I do mean ordered and not sorted.

Motivation:

I want to iterate over an ordered collection. eg

def most_important(priorities):
    for p in priorities:
        print p

In this case the fact that priorities is ordered is important. What kind of collection it is is not. I'm trying to live duck-typing here. I have frequently been dissuaded by from type checking by Pythonistas.

If the collection is truly arbitrary (meaning it can be of any class whatsoever), then the answer has to be no .

Basically, there are two possible approaches:

  1. know about every possible class that can be presented to your method, and whether it's ordered;
  2. test the collection yourself by inserting into it every possible combination of keys, and seeing whether the ordering is preserved.

The latter is clearly infeasible. The former is along the lines of what you already have, except that you have to know about every derived class such as collections.OrderedDict ; checking for dict is not enough.

Frankly, I think the whole is_ordered check is a can of worms. Why do you want to do this anyway?

Update: In essence, you are trying to unittest the argument passed to you. Stop doing that, and unittest your own code. Test your consumer (make sure it works with ordered collections), and unittest the code that calls it, to ensure it is getting the right results.

In a statically-typed language you would simply restrict yourself to specific types. If you really want to replicate that, simply specify the only types you accept, and test for those. Raise an exception if anything else is passed. It's not pythonic, but it reliably achieves what you want to do


Well, you have two possible approaches:

  1. Anything with an append method is almost certainly ordered; and
  2. If it only has an add method, you can try adding a nonce-value, then iterating over the collection to see if the nonce appears at the end (or, perhaps at one end); you could try adding a second nonce and doing it again just to be more confident.

Of course, this won't work where eg the collection is empty, or there is an ordering function that doesn't result in addition at the ends.

Probably a better solution is simply to specify that your code requires ordered collections, and only pass it ordered collections.

I think that enumerating the 90% case is about as good as you're going to get (if using Python 3, replace basestring with str). Probably also want to consider how you would handle generator expressions and similar ilk, too (again, if using Py3, skip the xrangor):

generator = type((i for i in xrange(0)))
enumerator = type(enumerate(range(0)))
xrangor = type(xrange(0))
is_ordered = lambda seq : isinstance(seq,(tuple, list, collections.OrderedDict,
                                          basestring, generator, enumerator, xrangor))

If your callers start using itertools, then you'll also need to add itertools types as returned by islice, imap, groupby. But the sheer number of these special cases really starts to point to a code smell .

如果没有订购列表怎么办,例如[1,3,2]?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM