简体   繁体   中英

How to find if a number in a list is in a interval of two numbers in a list?

I have two sorted lists of same length, eg:

first_list = [3, 5, 15, 19, 23]
second_list = [0, 11, 22, 34, 43]

I wish to know if the numbers of the first list are in the interval formed by the two numbers in a row from the second list. Then, i wish to print the value of the first list and the interval.

As an example:

3 in range(0,11) # True
5 in range(0,11) # True
15 in range(0,11) # False, next
15 in range(11,22) # True

and so on.

first_list = [3, 5, 15, 19, 23]
second_list = [0, 11, 22, 34, 43]

aux = 0
count = 1
n_iterations = len(first_list)
iteration = 0
while iteration != n_iterations:
    iteration += 1
    for i in first_list: 
        counter = first_list.index(i)
        try:        
            interval = range(second_list[aux],second_list[count])        
            if i in interval:
                print(i, 'in', interval)
            if i not in interval:    
                aux += 1
                count += 1    
                interval = range(second_list[aux], second_list[count])            
                if i in interval:
                    print(i, 'in' ,interval)
        except IndexError:
            break

The code i've tried does actually work. But it seems so inefficient and 'hard-to-read' that there must be another way to do it.

edit: Since the question was updated, I updated my answer a little. I happily concede that this solution is not optimal, and takes more time than user7440787's solution. I focused more on the "hard-to-read" than "inefficient" part of the problem.


First, my answer, then some explanations.

first_list = [3, 5, 15, 19, 23]
second_list = [0, 11, 22, 34, 43]

for low,high in zip(second_list, second_list[1:]):
    for val in first_list:
        if low <= val <= high:
            print("{} is in {}".format(val, (low, high)))

Output:

3 is in (0, 11)
5 is in (0, 11)
15 is in (11, 22)
19 is in (11, 22)
23 is in (22, 34)

This gives you simple elegance, while still being readable. It's always a fun challenge to stick everything on to one line, but the code is much easier to handle when you break it into significant parts. Of course, there are other ways you could have done this, but this shows off quite a few niceties of python.

zip(second_list, second_list[1:]) goes through the list of pairs in second_list. The [1:] slices the list to be all but the first element of it, while the zip takes the two views of the list and yields a tuple for each pair, which then get assigned to low and high.

low <= val <= high is a logical error in C, C++ or C#, but is perfectly right in python. It is defined as "low <= val and val <= high", which is exactly what you're looking for in this case.

Using str.format is an easy way to output all types of variables in python.

If you want to print the first time an entry is not in the list, then you need:

first_list = [3, 5, 15, 19, 23]
second_list = [0, 11, 22, 34, 43]
regions = list(zip(second_list[:-1],second_list[1:]))
n, i = 0, 0
print_stm = '%i %s in range(%i,%i)'
while n < len(regions) and i < len(first_list):
    if regions[n][0] <= first_list[i] <= regions[n][1]:
        print(print_stm % ((first_list[i], '') + regions[n]))
        i+=1
    else:
        print(print_stm % ((first_list[i], 'not') + regions[n]))
        n+=1

The result is:

3 in range(0,11)
5 in range(0,11)
15 not in range(0,11)
15 in range(11,22)
19 in range(11,22)
23 not in range(11,22)
23 in range(22,34)

If you're only interested in knowing the intervals for each entry in first_list , you can simplify it to this:

first_list = [3, 5, 15, 19, 23]
second_list = [0, 11, 22, 34, 43]
regions = zip(second_list[:-1],second_list[1:])
intervals = [ (i, n) for i in first_list for n in regions if n[0] < i < n[1]]

The result is:

[(3, (0, 11)), (5, (0, 11)), (15, (11, 22)), (19, (11, 22)), (23, (22, 34))]

One line solution for all possible pairs of ranges defined by the second list.

Your code seems fine but here is a shorter version:

# define all duo pairs based on `second_list`
all_pairs = [[second_list[p1], second_list[p2]] for p1 in range(len(second_list)) for p2 in range(p1+1,len(second_list))]

results = list()
results.append([[element,"is in", (all_pairs[i][0],all_pairs[i][1])] for element in first_list for i in range(len(all_pairs)) if element in range(all_pairs[i][0],all_pairs[i][1])])

If I understood correctly, the above should work.

Output:

[[[3, 'is in', (0, 11)],
  [3, 'is in', (0, 22)],
  [3, 'is in', (0, 34)],
  [3, 'is in', (0, 43)],
  [5, 'is in', (0, 11)],
  [5, 'is in', (0, 22)],
  [5, 'is in', (0, 34)],
  [5, 'is in', (0, 43)],
  [15, 'is in', (0, 22)],
  [15, 'is in', (0, 34)],
  [15, 'is in', (0, 43)],
  [15, 'is in', (11, 22)],
  [15, 'is in', (11, 34)],
  [15, 'is in', (11, 43)],
  [19, 'is in', (0, 22)],
  [19, 'is in', (0, 34)],
  [19, 'is in', (0, 43)],
  [19, 'is in', (11, 22)],
  [19, 'is in', (11, 34)],
  [19, 'is in', (11, 43)],
  [23, 'is in', (0, 34)],
  [23, 'is in', (0, 43)],
  [23, 'is in', (11, 34)],
  [23, 'is in', (11, 43)],
  [23, 'is in', (22, 34)],
  [23, 'is in', (22, 43)]]]

Here's what i've done :

first_list = [3, 5, 15, 19, 23]
second_list = [0, 11, 22, 34, 43]

L = list(zip(second_list[:-1], second_list[1:]))
i = 0
n = 0
interval = L[i]

while  n < len(first_list):
    nb = first_list[n]
    while nb not in range(interval[0],interval[1]):
        print(nb, ' is not in range', interval)
        i += 1
        if i >= len(L):
            break
        interval = L[i]
    if i >= len(L):
        break
    print(nb, ' is in range', interval)
    n += 1

The output :

3  is in  range(0, 11)
5  is in  range(0, 11)
15  is not in  range(0, 11)
15  is in  range(11, 22)
19  is in  range(11, 22)
23  is not in  range(11, 22)
23  is in  range(22, 34)

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