0

I am pretty sure this question has been asked about a gazillion times, but I can not find a satisfying answer. I am trying to iterate through a list and find how many occurrences of 'B' are immediately preceded by 'A'. I have a solution, but I am sure it is far from perfect. In C++ I'd do something like (with about 10 variations):

int main()
{
    vector<char> charList={'A', 'B', 'D', 'B', 'C', 'A', 'B'};
    int count=0;
    char prevElem = '\0';
    for(auto x: charList)
    {
        if( x == 'B' && prevElem =='A')
            ++count;
        prevElem = x;
    }
    
    cout << "Count = " << count << endl;

    return 0;
}

What is the right way to do it in Python? I mean the simplest solution is obvious, but what should I do if the data I have is in the form of iterator with the lazy iterable under it and I do not want to go over that iterator twice?

wjandrea
  • 28,235
  • 9
  • 60
  • 81
Mark Z
  • 19
  • 2
  • Did you try and write the same algorithm in Python? – khelwood Jan 25 '21 at 01:00
  • Yes, that is what I mean by "far from perfect". My question is a bit more involved: What should I do if the data I have is in the form of iterator with the lazy iterable under it and I do not want to go over that iterator twice? – Mark Z Jan 25 '21 at 01:12
  • You can do the same thing you're doing in your C++ code. – khelwood Jan 25 '21 at 01:13
  • Python >= 3.8: `prev = object(); count = sum(1 for char in char_list if (prev, (prev := char)) == ('A', 'B'))`. – ekhumoro Jan 25 '21 at 01:46
  • 2
    A good place to start for problems like this is the [itertools recipes](https://docs.python.org/3/library/itertools.html#itertools-recipes), in this case `pairwise`. (`sum(map(lambda cc:cc==('A', 'B'), pairwise(charlist)))`). Unlike solutions using subscripting or slicing, this will work on an arbitrary sequence, including generators. – rici Jan 25 '21 at 01:52
  • 1
    @rici `map(lambda)` is ugly. A generator expression is nicer and shorter: `sum(cc==('A', 'B') for cc in pairwise(charlist))` – wjandrea Jan 25 '21 at 02:12
  • @wjandrea: fair enough. – rici Jan 25 '21 at 02:15
  • I guess the solution by @wjandrea above is what I was looking for! – Mark Z Jan 25 '21 at 02:25

4 Answers4

0

Try this code:

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

count = 0
for index in range(0, len(char_list)-1):
    if char_list[index] == 'A' and char_list[index+1] == 'B':
        count += 1

print('count :', count)

Try this new one:

char_list = ['A', 'B', 'D', 'B', 'C', 'A', 'B', 'A', 'B']
prev_char = ''

count = 0
for char in char_list:
    if char == 'B' and prev_char == 'A':
        count += 1
    prev_char = char

print('count :', count)
Robot Jung
  • 367
  • 4
  • 13
0

The simplest implementation would be the following:

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

count = 0
for i in range(len(array)-1):
  if array[i] == 'A' and array[i+1] == 'B':
    count += 1

print(count)
ahmadjanan
  • 298
  • 2
  • 9
0

Previus solution will give an error for a list ending in A. I would suggest to start from index 1 and look at the previous one

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

count = 0
for index in range(1, len(char_list)):
    if char_list[index] == 'B' and char_list[index-1] == 'A':
        count += 1

print('count :', count)
FrancecoMartino
  • 409
  • 2
  • 5
0

My version of Robot Jung's answer:

def findAb(data):
    iterator = iter(data)
    prevElem = ''

    for curElem in iterator:
        yield int(curElem == 'B' and prevElem == 'A')
        prevElem = curElem

if __name__ == '__main__':
    data =  ['A', 'B', 'D', 'B', 'C', 'A', 'B']

    count = sum( d for d in findAb(data))
    print (count)
Mark Z
  • 19
  • 2
  • How is this an improvement over the much simpler and clearer solution given by RobertJung (i.e. the second one)? – ekhumoro Jan 25 '21 at 02:11
  • I cleaned up mine slightly, please check again. Whether that is an improvement I do not know. Still learning. I guess it just makes the intent slightly more visible to the user – Mark Z Jan 25 '21 at 02:18
  • 1
    On the new version: why not just increment the count inside `findAb` and return it? There's no need for a generator function here. – ekhumoro Jan 25 '21 at 02:21
  • Probably you are right. Too many available tools – Mark Z Jan 25 '21 at 02:35