1

I have two lists both containing numbers, and I want to check if the numbers from one list are numbers between every two numbers from the other list? The "other" list has ordered numbers so that every two numbers is an interval like 234, 238, 567, 569, 2134, 2156.

ListA = [200, 765, 924, 456, 231]

ListB = [213, 220, 345, 789, 12, 45]

I want to check if ListA[0:] is a number between either ListB[0:1] or [2:3] etc.

I have tried this:

for i in range(0,len(ListB), 2):
    for x in ListA:
        if i < x < (i:i+2):
            print 'within range'

But I get a syntax error for the "i:i+2" :(

tshepang
  • 12,111
  • 21
  • 91
  • 136
user1882385
  • 169
  • 2
  • 9
  • I'm sorry, but I still don't get what you want. What do you mean "I want to check if ListA[0:] is a number between either ListB[0:1] or [2:3]"? ListA[0:] is another list, not a number. – mgilson Dec 18 '12 at 19:02
  • What did you mean by `x < (i:i+2)`? If you can state it in English, someone can help you translate it to Python. – abarnert Dec 18 '12 at 19:02
  • We have so many different answers I think a clarification is needed :) – arynaq Dec 18 '12 at 19:09
  • As a side note, you normally want to name Python variables in lowercase, like `list_a` and `list_b` instead of `ListA` and `ListB`. (You may have noticed that StackOverflow highlighted your variable names as if they were types instead of variables. That's why that happened.) – abarnert Dec 18 '12 at 19:09
  • Sorry, what I meant by ListA[0:] is each item from ListA, and ListB[0:1], [2:3] every two items from ListB. – user1882385 Dec 19 '12 at 10:11

3 Answers3

4

If what you want to do is make sure that all items in list A are within at least one of the intervals in list B:

>>> listA = [200, 765, 924, 456, 231]
>>> listB = [213, 220, 345, 789, 12, 45]

>>> intervals = zip(*[listB[i::2] for i in range(2)])

>>> [any(low < x < high for low, high in intervals)
                    for x in listA]
[False, True, False, True, False]
Mike Sherrill 'Cat Recall'
  • 91,602
  • 17
  • 122
  • 185
voithos
  • 68,482
  • 12
  • 101
  • 116
  • 1
    Variations on the theme: `intervals = [listB[i:i+2] for i in xrange(0,len(listB),2)]` or `intervals = zip(*[iter(listB)]*2)` – jfs Dec 18 '12 at 19:41
  • @J.F.Sebastian: Nice! That last one is awesome! Really clever usage of the common `[obj] * n` single-reference pitfall. – voithos Dec 18 '12 at 20:13
  • 1
    @voithos: It is a standard Python idiom to iterate over an iterable n items at a time. See [What is the most “pythonic” way to iterate over a list in chunks?](http://stackoverflow.com/questions/434287/what-is-the-most-pythonic-way-to-iterate-over-a-list-in-chunks). "clever" is pejorative term when applied to code: *"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." – Brian W. Kernighan* – jfs Dec 18 '12 at 21:22
  • @J.F.Sebastian: Hmm, I really wish I knew about said idiom a lot earlier - I've hacked my way around that problem more than once without knowing of such an elegant method (in my opinion). And perhaps I should rephrase: I feel like it's a interesting usage of how the `*` operator functions in this case. – voithos Dec 18 '12 at 21:36
  • @J.F.Sebastian: +1, because `zip`ping over `*[iter(iterable)]*n` is a standard Python idiom that people should learn how to read and understand. But it's usually better to wrap it up in a function whose name explains what you're doing—especially since you can just copy and paste that function from the recipes in the `itertools` docs, or `pip install more-itertools`. When people see `grouper(2, listB)` it's more immediately obvious what it means. – abarnert Dec 19 '12 at 19:17
2

I think this is what you want, although it's not that clear:

for i in range(0, len(ListB), 2):
    for x in ListA:
        if ListB[i] < x < ListB[i+1]:
            print 'within range'

You're right in your intuition that you can i:i+2 sort of represents a "range", but not quite like that. That syntax can only be used when slicing a list: ListB[i:i+2] returns a smaller list with just 2 elements, [ListB[i], ListB[i+1]], just as you expect, but i:i+2 on its own is illegal. (If you really want to, you can write slice(i, i+2) to mean what you're aiming at, but it's not all that useful here.)

Also, from your description, you want to compare x to the values ListB[i] and ListB[i+1], not just i and i+1 as in your code.

If you wanted to use the slice to generate a range, you could do so, but only indirectly, and it would actually be clumsier and worse in most ways:

for i in range(0, len(ListB), 2):
    brange = range(*ListB[i:i+2])
    for x in ListA:
        if x in brange:
            print 'within range'

But this is checking for a half-open range rather than an open range, and it requires creating the list representing the range, and walking over the whole thing, and it will only work for integers. So, it's probably not what you want. Better to just explicitly use ListB[i] < x < ListB[i+1].

You might want to consider whether there's a more readable way to build a list of pairs of elements from ListB. Without yet knowing about itertools and list comprehensions or generator expressions (I assume), you'd probably have to write something pretty verbose and explicit, but it might be useful practice anyway.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • You said, "You might want to consider whether there's a more readable way to build a list of pairs of elements from ListB." [See the zip() function.](http://docs.python.org/2/library/functions.html#zip) – Mike Sherrill 'Cat Recall' Dec 18 '12 at 19:20
  • @Catcall: I'm trying to get the OP to figure out a way to write this himself, not hand him code that he doesn't understand. – abarnert Dec 18 '12 at 19:39
  • 1
    btw, [`an_int in range` is a O(1) operation in Python 3](http://hg.python.org/cpython/file/b6ced7bd7d96/Objects/rangeobject.c#l360) though for `step == 1` case the explicit comparison might be better – jfs Dec 18 '12 at 19:42
  • @J.F.Sebastian: Yes, and I actually do encourage people who are clearly learning Python 3 to use `in` with `range`s for that purpose. But people who are clearly learning Python 2 (as you can tell from his `print` statement), it will just confuse them, or at best tantalize them with hints of how things would be better if they put things off until their teacher/web course/whatever decided to teach Python 3… – abarnert Dec 18 '12 at 19:51
  • This will probably also work! I'm going to try it, thank you so much! :) – user1882385 Dec 19 '12 at 10:15
0
for i in range(0,len(ListB)-1, 2): #offest 1 less than the length
    for x in ListA:
        if ListB[i] < x < ListB[i+1]: #check if it is between ListB's elements
            print 'within range'

at least assuming I understand what you want ...

Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
  • You don't need the `len(ListB)-1`. Look at what `range(0, 6, 2)` returns—it's guaranteed to be the same as `range(0, 5, 2)`. (Of course if `ListB` had an odd length that might not be true, but that seems like an invalid input for the OP, so it _should_ raise an error.) – abarnert Dec 18 '12 at 19:10
  • maybe ... I figured that was beyond the scope of the question ... and I figured he would always want a valid index ... – Joran Beasley Dec 18 '12 at 19:38
  • Will check this as well, if the other solutions would not work, but they probably will, thanks everyone! – user1882385 Dec 19 '12 at 10:17