rahlf23
rahlf23

Reputation: 9019

Determine if a character appears before first occurrence of another character

I want to be able to input a list of letters (there are only four options for letters in the list), however the list can be up to ten or so items long, for example:

letter_options = ['A', 'B', 'C', 'D']

s = ['B', 'C', 'A', 'C', 'D', 'A']
s = ['C', 'A', 'D', 'C', 'A']
s = ['A', 'B', 'A', 'A', 'D', 'B', 'B']

My question is how would I go about determining if 'B' occurs before a 'D' or an 'A' occurs? If 'B' does not exist in the list, then the code would output 0. If 'B' does occur before an 'A' or 'D', then the code would output 1.

Here is what I have, but it does not work for the case where 'B' does not occur.

letters = ['A', 'A', 'A', 'A']
fkt = []

check = ' '.join(letters).split('B')[0].split()
if letters!=[] and letters[0]=='B':
    fkt.append(1)
elif letters!=[] and any(idx in check for idx in ['A', 'D']):
    fkt.append(0)
else:
    fkt.append(1)

Upvotes: 1

Views: 447

Answers (2)

cs95
cs95

Reputation: 403128

If ['B', 'C', 'A', 'C', 'D', 'A'] is your list and you want to find out whether 'B' precedes 'D', you can convert your list to a string and then use str.find:

In [141]: l = ''.join(['B', 'C', 'A', 'C', 'D', 'A'])

In [148]: l[:max(0, l.find('D'))].find('A') > -1
Out[148]: True

In general,

In [153]: def foo(l, c1, c2): # is c2 before c1?
     ...:     return l[:max(0, l.find(c1))].find(c2) > -1
     ...: 

In [154]: foo(l, 'B', 'D')
Out[154]: False

In [155]: foo(l, 'D', 'B')
Out[155]: True   

str.find returns -1, so you can handle no-matches gracefully, since a splice to 0 ([:0]) returns an empty list.

An even simpler alternative is 0 <= l.find('X') < l.find('Y') as suggested by VPfB:

def foo(l, c1, c2): # is c2 before c1?
    return `0 <= l.find('c2') < l.find('c1')`

Upvotes: 2

akuiper
akuiper

Reputation: 215117

You could try this method:

def code(lst):
    for i in lst:
        # loop through the list, if find the element A or D, return 0 and break out of 
        # the loop
        if i in ['A', 'D']:
            return 0
        # if find B, return 1 and break out of the loop
        elif i == 'B':
            return 1
    # if not find B at all return 0 and break out of the loop
    return 0

s1 = ['B', 'C', 'A', 'C', 'D', 'A']
s2 = ['C', 'A', 'D', 'C', 'A']
s3 = ['A', 'B', 'A', 'A', 'D', 'B', 'B']

code(s1)
#1

code(s2)
#0

code(s3)
#0

Or equivalently:

bfirst = 0
for i in lst:
    if i in ['A', 'D']:
        bfirst = 0
        break
    elif i == 'B':
        bfirst = 1
        break

Justification:

Use a simple for loop, and if else to check values, if 'AD' were found firstly, then bfirst is 0 and short circuit (break out of the loop), since there is no need to check other elements anymore; Similarly if 'B' was found firstly, then assign bfirst 1 and short circuit (break out of the loop) for the same reason above; If you have a long list and very few options of letters, this would potentially be very efficient since it only checks a few letters at the beginning of the list without having to thoroughly loop through the list; Under the worst cases (the list is totally made up irrelevant letters), it is still O(N), one pass of the list.

Upvotes: 1

Related Questions