简体   繁体   中英

Find the first element in a list where all subsequent values increment by one

I would like to find the value in a list, after which all other values increase by 1 only.

# Input
my_list1 = [2, 5, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
my_list2 = [6, 7, 9, 11, 12, 14, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28]
my_list3 = [5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25]
# Output
my_list1 = 15
my_list2 = 20
my_list3 = 18

I was thinking about looping backwards through the lists and when the decrease is larger than 1, extract the value at this position.

for x in reversed(my_list1):
    if x decrease > 1:
        print(x)

Here's an itertools based one, useful if we have a very long list, so we don't have load it into memory. Here dropwhile will drop values from the iterable while the condition holds, we only need to take the next element in the resulting iterable. Note that next has a default argument, which we can just set to None to avoid having the StopIteration error being raised:

from itertools import tee, dropwhile

def first_diff(it):
    i, j = tee(reversed(it), 2)
    next(j)
    return next((dropwhile(lambda e: e==(next(j)+1), i)), None)

first_diff(my_list1)
# 15
first_diff(my_list2)
# 20
first_diff(my_list3)
# 18

You could zip() thereversed() lists into pairs, then use next() to get the first pair where the difference is greater than 1. We can then unpack the first item from the result.

def first_diff_pair(lst):
    return next(
        (fst for fst, snd in zip(reversed(lst), reversed(lst[:-1])) if fst - snd > 1),
        None,
    )

To avoid next() returning StopIteration when no result is found and the iterator is exhausted, we can set the default value to None .

Output:

>>> first_diff_pair([2, 5, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24])
15
>>> first_diff_pair([6, 7, 9, 11, 12, 14, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28])
20
>>> first_diff_pair([5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25])
18

There are several possibilities with list comprehensions. Here I collect every number that increased by more then one, store them in a list and show the last one:

print([my_list1[i+1] for i in range(len(my_list1)-1) if my_list1[i+1] - my_list1[i] > 1][-1])
print([my_list2[i+1] for i in range(len(my_list2)-1) if my_list2[i+1] - my_list2[i] > 1][-1])
print([my_list3[i+1] for i in range(len(my_list3)-1) if my_list3[i+1] - my_list3[i] > 1][-1])

Well, I tried this, and it worked, but there maybe better and more efficient solutions to it too,

l = len(my_list1) - 1
for x in reversed(my_list1):
    if my_list1[l] - my_list1[l - 1] == 1:
      l -= 1
      continue
    else:
      print(x)
      break

This is a solution with no duplicate code:

my_list1 = [2, 5, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
my_list2 = [6, 7, 9, 11, 12, 14, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28]
my_list3 = [5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25]

def getIncreaseStartPoint(nums):
  i = len(nums) - 1
  while (nums[i] - nums[i - 1] == 1):
    i -= 1
    if (i == 0):
      return nums[0]
  return nums[i]

print("mylist_1 =", getIncreaseStartPoint(my_list1))
print("mylist_2 =", getIncreaseStartPoint(my_list2))
print("mylist_3 =", getIncreaseStartPoint(my_list3))

Here is a basic loop-based implementation.

def get_first_diff(my_list):
    reversed_iter = reversed(my_list)
    last = next(reversed_iter)
    for v in reversed_iter:
        if last - v != 1:
           return last
        last = v
    return None

Here is my attempt:

my_list1 = [2, 5, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]

tmplist = [x - i for i, x in enumerate(my_list1)]
first = my_list1[tmplist.index(tmplist[-1])]
# result 15

How it works:

# tmplist is [2, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6]

Repeating numbers show places of increasing sequences (by +1) in the original list. Last item ( tmplist[-1] ) is 6, we want to get the position of the first such item ( tmplist.index(...) ), because there the sequence starts. Finally we look up the value at that index ( my_list1[...] )

Similar to the Splitting list based on missing numbers in a sequence , you can use itertools.groupby to group consecutive runs of numbers, and from there to get the first value of the last run:

from itertools import groupby

my_list = [2, 5, 7,8,9,10,11,12,13, 15,16,17,18,19,20,21,22,23,24]
first_value = None
for _, group in groupby(enumerate(my_list), lambda x: x[1] - x[0]):
    first_value = next(group)[1]
print(first_value)
# 15

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