Checking sequential numbers with a specific condition - Python

I am trying to write a function that will check if a list has consecutive numbers, but with a very strange catch. The catch is that "a" can be used as a substitute for any integer, but at least 2 items in the list must be numbers. Also elements> = 1 (if not "a") and are integers. It can be assumed that the input will be of this shape, so there is no need to validate it. I'm new to coding, so I'd rather use loops over one liner as I'm not very familiar with using one liner yet.

For example:

>>>check_consecutive([1,2,"a","a",5,6,7,"a"])
True
>>>check_consecutive(["a","a","a","a",9,10])
True
>>>check_consecutive(["a","a","a","a",5])
False #Need at least 2 elements to be numbers
>>>check_consecutive([3,4,5,"a",6,7])
False
>>>check_consecutive(["a","a","a","a","a","a",2,3])
False

      

What I was trying to do:

def check_consecutive(lst):
 count = 0
 for i in range(len(lst)-1):
     if lst[i] == "a" or lst[i+1] == "a":
         count +=1
     elif lst[i+1] - lst[i] == 1:
         count +=1
 if count == len(lst)-1:
     return True
 return False

      

It doesn't work because it doesn't account for the "a" values. I'm not sure how to do this. Thanks in advance for any help.

+3


source to share


6 answers


Try the following. It fits all of your test cases and I was holding back the one-liners:

def check_consecutive(lst):
    # Check for the number of non-"a" entries in the list:
    if len([x for x in lst if x != "a"]) < 2:
        return False

    # Get the first non-a value (ASSUMPTION: this is a number)
    first_number = next((e for e in lst if e != "a"), None)

    # Find the index of the first number
    first_index = lst.index(first_number)

    # Find the difference between the first number and its index
    diff = first_number - first_index

    # Based on the final example - false if negative values would be used:
    if diff < 0:
        return False

    # Create a new list - replace a with their index plus the difference we found
    # If the list is consecutive, this difference will be consistent for all values
    all_numbers = []
    for i, x in enumerate(lst):
        if x == "a":
            all_numbers.append(i + diff)
        else:
            all_numbers.append(x)

    # Check if the values are now consecutive or not!
    if all(all_numbers[i+1] == all_numbers[i] + 1 for i in range(len(all_numbers) - 1)):
        return True
    else:
        return False

print check_consecutive([1,2,"a","a",5,6,7,"a"])
#True
print check_consecutive(["a","a","a","a",9,10])
#True
print check_consecutive(["a","a","a","a",5])
#False #Need at least 2 elements to be numbers
print check_consecutive([3,4,5,"a",6,7])
#False
print check_consecutive(["a","a","a","a","a","a",2,3])
#False

      



If you want to see how some one-liners work, you can reduce the function a bit like this:

def check_consecutive(lst):
    # Check for the number of non-"a" entries in the list:
    if len([x for x in lst if x != "a"]) < 2:
        return False

    # Get the first non-a value (ASSUMPTION: this is a number)
    first_number = next((e for e in lst if e != "a"), None)

    # Find the index of the first number
    first_index = lst.index(first_number)

    # Find the difference between the first number and its index
    diff = first_number - first_index

    # Based on the final example - false if negative values would be used:
    if diff < 0:
        return False

    if all(x == "a" or x == i + diff for i, x in enumerate(lst)):
        return True
    else:
        return False

      

+2


source


You have a working solution here. I know you said you didn't want a list comprehension (I edit it with loops for

so you can understand):

def check_consecutive(a):
    b = [(next(y for y in a if y!='a')-a.count('a') if a[0] == 'a' else a[0])+i if x=='a' else x for i, x in enumerate(a)]
    return len(a) - a.count('a') >= 2 and b[0] >= 0 and range(b[0],b[-1]+1) == b

      



The explanation of the list can be translated into the following:

for i,x in enumerate(a):
     if x == 'a':
         if a[0] == 'a':
             #              |---> Gets first integer from list
             new_lst.append(next(x for x in a if x != 'a') - a.count('a'))
         else:
             new_lst.append(a[0]+i)
     else:
         new_lst.append(x)

      

+1


source


This is not a good solution. But I tried the list back like this:

def check_consecutive(lst):
  last = 0
  number_count = len(lst) - lst.count('a')
  # Check count of numbers and return if less than 2
  if number_count < 2:
      return False

  for i in reversed(range(len(lst))):
      # last 0 means no numbers encountered yet
      if not last:
          last = lst[i] if lst[i] != "a" else 0
          continue
      else:
          # If current element is number check consecutive property
          if lst[i] != "a" and last - lst[i] != 1:
              return False

          # Recalculate last
          last -= 1

          # If last falls below permissible range, return 
          if last < 1:
              return False

  # If all condition satisfied, it is a hit. Whew!!!
  return True

print check_consecutive([1,2,"a","a",5,6,7,"a"])
print check_consecutive(["a","a","a","a",9,10])
print check_consecutive(["a","a","a","a",5])
print check_consecutive([3,4,5,"a",6,7])
print check_consecutive(["a","a","a","a","a","a",2,3])

      

+1


source


It works for your examples (py 2.7):

def check_consecutive(lst):
    # what could be the list
    cond = [0,1]
    n_sum = False
    for x in lst:
        if not(cond[1]) and x!= 'a':
            n_sum = True;
            if (cond[0] - x) != (lst.index(cond[0]) - lst.index(x)): 
                return False
            elif x <= lst.index(x):
                return False
        if x!='a' and cond[1]:
            cond[0] = x;
            cond[1] = 0;
    print cond
    return n_sum

      

+1


source


All of your test tables assume the sequence starts or ends with an actual number (or both). Assuming it does, we can find a fairly simple explicit solution in O (n) time and O (1) space.

def check_consecutive(seq):
    PLACEHOLDER = 'a'
    # O(n) check for preconditions
    if sum(obj != PLACEHOLDER for obj in seq) < 2:
        return False
    if isinstance(seq[0], int):
        # first element known, incrementing
        incrementing = True
        delta = 1
    else:
        # last element known, decrementing
        incrementing = False
        delta = -1
    # iterate from first or last element
    iterator = iter(seq) if incrementing else reversed(seq)
    # consume first value
    previous_item = next(iterator)
    # check if our assumption is correct
    assert previous_item != PLACEHOLDER
    # O(n) check for valid sequence
    for item in iterator:
        # figure out expected placeholder value
        if item == PLACEHOLDER:
            item = previous_item + delta
        # check if next value matches requirements of valid solution
        if item <= 0 or item != (previous_item + delta):
            return False
        previous_item = item
    return True

assert check_consecutive([1,2,"a","a",5,6,7,"a"]) is True
assert check_consecutive(["a","a","a","a",9,10]) is True
assert check_consecutive(["a","a","a","a",5]) is False
assert check_consecutive([3,4,5,"a",6,7]) is False
assert check_consecutive(["a","a","a","a","a","a",2,3]) is False

      

+1


source


All other answers probably work, but I tried to keep everything as simple and simple as possible, I hope this helps :) The code should be clear.

def check_consecutive(input_list):
    # First find the first element that is not equal to a to figure out the start of the sequence
    start_seq = None
    for i, el in enumerate(input_list):
        if el != 'a':
            # Now we know the number the sequence should start with.
            # For example the first 2 elements are a, and the first "non-a" element is 5
            # Then the loop breaks when el = 5, and i = 2, meaning the start should be 3
            start_seq = el - i
            break

    # If the whole list exists of a's, then start will still be None and the function should return false
    if start_seq is None:
        return False

    if start_seq < 1:
        return False

    # Now we can loop over the list, keep replacing a by what they should be
    # Create some values for bookkeeping
    num_n = 0
    old_value = start_seq - 1
    for el in input_list:
        if el != 'a':
            num_n += 1
            if el != (old_value + 1):
                return False

        # increment old value
        old_value += 1

    if num_n < 2:
        return False

    return True

      

+1


source







All Articles