Reputation:
I'd like to count the amount of items in an array before a consecutive amount of zeroes which is inputted by the user.
['1', '0', '1', '0', '0', '0', '0', '0', '0', '0', 'E']
For example, if the user inputs 3, there are three items in the list before a consecutive amount of three zeroes.
At the moment my code checks for the amount of consecutive zeroes and returns based on that - how can I change this to also gain the value of items before the consecutive instance?
LargeBlock = max(sum(1 for _ in g) for k, g in groupby(line) if k == '0')
Upvotes: 2
Views: 147
Reputation: 226396
This is much easier if you first convert the list to string:
row = ['1', '0', '1', '0', '0', '0', '0', '0', '0', '0', 'E']
seats = ''.join(row[:-1])
Once in string form, it is easy to search for a block of seats:
block = '0' * n
location = s.find(block)
Here is all the code in a single function:
def search(available, required):
'Return the first available block of seats on a given row'
row = available[-1]
seats = ''.join(available[:-1])
block = '0' * required
i = seats.find(block)
if i == -1:
raise ValueError('no block large enough')
return '%s%d-%s%d' % (row, i+1, row, i+required)
if __name__ == '__main__':
print search(['1', '0', '1', '0', '0', '0', '0', '0', '0', '0', 'E'], required=3)
If you want to stick with your original itertools.groupby approach, then you need to track both the position and values as you loop. This is a job for enumerate():
>>> def is_occupied(t):
seat, occupied = t
return occupied
>>> def seat_number(t):
seat, occupied = t
return seat
>>> required = 3
>>> row = ['1', '0', '1', '0', '0', '0', '0', '0', '0', '0', 'E']
>>> for occupied, groups in groupby(enumerate(row[:-1]), key=is_occupied):
if occupied == '0':
seats = list(map(seat_number, groups))
if len(seats) >= required:
print(seats[:required])
Eventhough groupby() can be made to work for you, it is tricky to use with a stream of tuples (such as that generated by enumerate()). If you're aiming for clarity, it is something better to skip the functional programming composition tricks and just look normally.
Here is a straight-forward, non-functional approach:
>>> cumulative_open = 0
>>> row_letter = row[-1]
>>> row = ['1', '0', '1', '0', '0', '0', '0', '0', '0', '0', 'E']
>>> required = 3
>>> row_letter = row[-1]
>>> cumulative_open = 0
>>> for i, occupied in enumerate(row[:-1], 1):
if occupied == "1":
cumulative_open = 0
continue
cumulative_open += 1
if cumulative_open >= required:
print('%s%d-%s%d' % (row_letter, i-required+1, row_letter, i))
break
else:
print("Not enough open seats")
E4-E6
Upvotes: 5
Reputation: 43457
Just for fun.... A very basic Theatre/Row manager.
class Row():
class SeatOccupiedException(Exception):
pass
def __init__(self, seats):
"""
Create a theatre row with seats.
seats ::= number of seats in the row
"""
self.seats = [False]*seats
def get_seats(self, group_size=1, empty=True):
"""
Get seats from the row in chunks according to group size.
Can get empty or non-empty seats.
group_size ::= amount of seats needed.
empty ::= should the seats be empty or not?
"""
ret = []
current_seats = []
for idx, seat in enumerate(self.seats, 1):
if seat != empty:
current_seats.append(idx)
if len(current_seats) >= group_size:
ret.append(current_seats[-group_size:])
return ret
def occupy_seats(self, seats):
"""
Occupy some seats
"""
for seat in seats:
if self.seats[seat]:
raise SeatOccupiedException()
self.seats[seat] = True
def vacate_seats(self, seats):
"""
Vacate some seats
"""
for seat in seats:
self.seats[seat] = False
class Theatre():
class RowAlreadyExistsException(Exception):
pass
def __init__(self, rows=None, seats_per_row=10):
"""
Create a theatre with rows, each row has seats.
rows ::= a list of the names for each row
seats_per_row ::= number of seats in the row
Examples:
t = Theatre(['A', 'B', 'C'])
=> produces a theatre with 3 rows (A,B,C) with 10 seats
t = Theatre('ABCDEFG', 3)
=> produces a theatre with 7 rows (A,B,C,D,E,F,G) with 3 seats
"""
self.rows = {}
if rows:
for row in rows:
self.add_row(row, seats_per_row)
def add_row(self, row_id, seats):
"""
Add a row to the theatre
row_id ::= the name of the row
seats ::= number of seats in the row
"""
if row_id in self.rows:
raise RowAlreadyExistsException()
self.rows[row_id] = Row(seats)
def get_available_seats(self, group_size, row_id=None):
"""
Get all seats available for a group of a certain size
Can specify a specific row or all of them
group_size ::= how many available seats are needed
row_id ::= specify a certain row if desired
"""
ret = {}
def get_row(k):
ret[k] = self.rows[k].get_seats(group_size)
rows = [row_id] if row_id else self.rows
for row_id in self.rows:
get_row(row_id)
return ret
def occupy_seats(self, row_id, seats):
"""
Occupy some seats
"""
self.rows[row_id].occupy_seats(seats)
def vacate_seats(self, row_id, seats):
"""
Vacate some seats
"""
self.rows[row_id].vacate_seats(seats)
Upvotes: 0
Reputation: 239513
seats, wanted = ['1', '0', '1', '0', '0', '0', '0', '0', '0', '0', 'E'], 3
from itertools import groupby
for occ, grp in groupby(enumerate(seats[:-1], 1), key = lambda x: x[1]):
if occ == '0':
available = list(grp)
if len(available) >= wanted:
print([seats[-1] + str(item[0]) for item in available[:wanted]])
# ['E4', 'E5', 'E6']
Upvotes: 1