Reputation: 1863
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
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
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
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