Christina Zhou
Christina Zhou

Reputation: 1863

Count which cycle of the alphabet this letter is in [python]

I have this alphabetic cycle A B C D which represent the phase an item is in. An item can cycle through the phase more than once, so I need to find out if an item is in its first phase A, or its second phase A.

Letters can be missing which makes this a bit tricky. See correct outputs:

test_1 = ['A','B','C','D','A','B']
output_1 = [1,1,1,1,2,2]

test_2 = ['A','B','D','A','B','C']
output_2 = [1,1,1,2,2,2]

test_3 = ['B','A','B','C']
output_3 = [1,2,2,2]

Note that in test_2 we accurately note the first occurrence of phase C is in the 2nd cycle.

My attempts are below:

import itertools

test_1 = ['A','B','C','D','A','B']
output_1 = [1,1,1,1,2,2]

test_2 = ['A','B','D','A','B','C']
output_2 = [1,1,1,2,2,2]

test_3 = ['B','A','B','C']
output_3 = [1,2,2,2]

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


def count_phases(phase_list):
    '''
    We will see whether this is the 1st phase A, or the 2nd phase A.
    :param phase_list:
    :return: int list
    '''
    phase_counts = []
    valid_iter = itertools.cycle(valid_phase_seq)
    count = 1

    # failed approach #2
    while len(phase_counts) != len(phase_list):
        for valid_phase in valid_iter:
            for curr_phase in phase_list:
                if valid_phase == curr_phase:
                    phase_counts.append(count)
            count += 1

    # failed approach #1
    # for curr_phase in phase_list:
    #     # Look at a phase
    #     curr_valid = next(valid_iter)
    #
    #     # We are in another cycle
    #     if curr_valid == 'A' and len(phase_counts) > 1:
    #         count += 1
    #         valid_iter = itertools.cycle(valid_phase_seq)
    #         curr_valid = next(valid_iter)
    #
    #     # We are in the same cycle
    #     #if curr_phase == curr_valid:
    #     phase_counts.append(count)

    return phase_counts

Upvotes: 1

Views: 78

Answers (3)

Tomerikoo
Tomerikoo

Reputation: 19432

Well, Karl beat me to it with a super simple solution. I on the other hand got it a little more complicated but will post anyway as I already put the time to it...

My idea was to use a cyclic counter with a mapping between each letter to an index. This way we loop on the letters and add one to each index up to that letter, cyclicly. Goes something like:

from itertools import count

def phase_count(phases):
    letters_index = {'A': 0, 'B': 1, 'C': 2, 'D': 3}
    counts = [0 for _ in letters_index]
    size = len(counts)

    res = []
    last_index = 0
    for letter in test_2:
        for index in count(last_index):
            counts[index%size] += 1
            if index % size == letters_index[letter]:
                res.append(counts[index%size])
                last_index = index + 1
                break
    return res

Upvotes: 0

Karl Knechtel
Karl Knechtel

Reputation: 61617

Trying to cycle through the valid phases is overthinking it. Just cycle through the actual data:

def number_cycles(phases):
    cycles = []
    current_cycle, previous_phase = 1, None
    for current_phase in phases:
        if previous_phase is not None and previous_phase >= current_phase:
            current_cycle += 1
        previous_phase = current_phase # for next loop
        cycles.append(current_cycle)
    return cycles

Upvotes: 3

Code-Apprentice
Code-Apprentice

Reputation: 83557

I think you have too many loops. In psuedocode, I would do something like this:

for letter in phase_list
    if letter starts a new phase
        count += 1
    phase_counts.append(count)

Upvotes: 0

Related Questions