2015-07-24 14 views
5

Biorąc pod tablicę tekstu wejściowegoalgorytm Pythona do zrobienia w pytonic?

input_array = [ 
    'JUNK', 'Mon', 'JUNK', '10am', 'JUNK', '-', ' 5pm', 
    '6pm', '-', '9pm', 'JUNK', 'Tue', '10am', '-', 'JUNK', '5pm' 
] 

powinny być zamienione na JSON

[ 
    { 
    "weekday_name": "monday", 
    "starting_time": "10am", 
    "ending_time": "5pm" 
    }, 
    { 
    "weekday_name": "monday", 
    "starting_time": "6pm", 
    "ending_time": "10pm" 
    }, 
    ... 
] 

Choć jest to prosty algorytm, jestem zmuszony do tworzenia zmiennych tymczasowych, które są zwykle uważane non-pythonic.

Kod z brzydkich zmiennych tymczasowych

import pprint 

input_array = ['JUNK','Mon','JUNK','10am','JUNK','-','5pm','6pm','-','9pm','JUNK','Tue','10am','-','JUNK','5pm'] 

business_hours = [] 
start_hours = None 
end_hours = None 
current_day = None 
dash_found = False 

days_of_the_week = {} 
days_of_the_week['Mon'] = 'monday' 
days_of_the_week['Tue'] = 'tuesday' 
days_of_the_week['Wed'] = 'wednesday' 
days_of_the_week['Thu'] = 'thursday' 
days_of_the_week['Fri'] = 'friday' 
days_of_the_week['Sat'] = 'saturday' 
days_of_the_week['Sun'] = 'sunday' 

for x in input_array: 
    if x in days_of_the_week: 
     current_day = days_of_the_week[x]  
    elif x[0].isdigit() and dash_found == False: 
     starting_time = x   
    elif x == '-': 
     dash_found = True  
    elif x[0].isdigit() and dash_found == True: 
     ending_time = x 
     business_hours.append({"weekday_name":current_day,"starting_time":starting_time,"ending_time":ending_time}) 
     dash_found = False 


pprint.pprint(business_hours) 

mogę zrobić mój kod mniej brzydki i osiągnąć to samo bez konieczności tworzenia wielu zmiennych tymczasowych w Pythonie?

+1

są ustawione pozycje? Czy input_array [1] jest zawsze dniem? czy "Śmieci" oznaczają dowolną liczbę przedmiotów, których nie chcesz? – KameeCoding

+0

Czy to normalne, że macierzy brakuje na jeden dzień w godzinach 18-18? – Holt

+0

@Holt Oznacza to, że powinien zostać uwzględniony w tym samym dniu. (ten sam dzień, ale dwa godziny pracy) – wolfgang

Odpowiedz

6

Ponieważ dane są zawsze w tej samej kolejności:

# Here you remove all the cells in your array which are not a day of the week 
# or a time (not the call to "list" before filter object are not indexable in Python 3+) 
data = list(filter(lambda x: x in days_of_the_week or x[0].isdigit(), input_array)) 
while data: 
    # Get the first item available and remove it 
    curday = days_of_the_week[data.pop(0)] 
    # For each couple (start, end), add an item to business_hours 
    while data and data[0][0].isdigit(): 
     business_hours.append({ 
      'weekday_name': curday, 
      'starting_time': data[0], 
      'ending_time': data[1] 
     }) 
     data = data[2:] 

Istnieje z pewnością wiele sposobów na osiągnięcie tego, prawdopodobnie tkwić ze zmienną curday ponieważ trzeba je zapamiętać (można użyć najnowszy wpis w business_hours, ale byłoby to brzydsze, IMO).

Edytuj: Ktoś zasugerował zmianę mówiąc, że list nie jest konieczne. Ponieważ nie wiem, której wersji python używasz, zakładam, że python 3.0 jest obowiązkowe (filter są w pewnym sensie generator w python 3.0, więc nie mogą być indeksowane). Jeśli używasz python 2.0, list może nie być obowiązkowe.


Dla zabawy, tutaj jest jeden liner użyciu zmniejszenia (muszę powiedzieć, aby nie zrobić?):

from functools import reduce # Okay, okay, 2 lines! 
reduce (lambda r, x: r + [{'weekday_name': days_of_the_week[x]}] if x in days_of_the_week 
        else r + [{'weekday_name': r[-1]['weekday_name'], 'starting_time': x}] if len(r[-1]) == 3 
        else (r[-1].update({'starting_time': x}), r)[1] if len(r[-1]) == 1 
        else (r[-1].update({'ending_time': x}), r)[1], 
     filter(lambda x: x in days_of_the_week or x[0].isdigit(), input_array), []) 
+1

Jednym z kluczowych aspektów pisania kodu, który skrypt jest przezroczysty do późniejszych recenzji. Dlatego powinniśmy, o ile to możliwe, unikać stosowania lambda i kilku "trudnych" rozwiązań. Uwielbiam sposób, w jaki to robisz i ostatecznie też korzystam z tych skrótów - i lubię to :) - ale powinieneś także pamiętać o innych aspektach. – Geeocode

+2

@ GyörgySolymosi Rozumiem twój punkt widzenia, ale nie sądzę, że ma to zastosowanie: pierwsza linia (z lambda) jest łatwa do zrozumienia (filtrujesz pod konkretnym warunkiem), 2 pętle może potrzebuje jednego komentarza, ale nic Skomplikowane tutaj, gdy tylko wiesz, na jakiej strukturze danych pracujesz i jaki jest podział pytonów (które uważam za wymóg dla dowolnego użytkownika pythona). I (oczywiście), późniejszy przykład użycia 'reduce' był czystym' żartem'. Tak czy inaczej, to moja własna opinia, a to jest długi temat debaty;) – Holt

0

Poniższy skrypt jest dość wyrozumiały w kategoriach wejście, jako takie nie widzę sposobu na kilka zmiennych.

Dodałem kolejny przypadek testowy na niedzielę z trzema czasami otwarcia i trochę inaczej umieszczonym JUNKIEM.

import pprint 

input_array = [ 
    'JUNK', 'Mon', 'JUNK', '10am', 'JUNK', '-', ' 5pm', 
    '6pm', '-', '9pm', 'JUNK', 'Tue', '10am', '-', 'JUNK', '5pm', 
    "Sun ", " 8am", "- ", "JUNK", "MORE JUNK", " 9pm", "10am ", "-", " 1pm", " 6pm", "-", "8pm"] 

days_of_the_week = {'mon' : 'monday', 'tue' : 'tuesday', 'wed' : 'wednesday', 
    'thu' : 'thursday', 'fri' : 'friday', 'sat' : 'saturday', 'sun' : 'sunday'} 

business_hours = [] 
start = None 

for entry in input_array: 
    entry = entry.strip().lower() 
    if entry in days_of_the_week: 
     current_day = days_of_the_week[entry] 
    elif entry[0].isdigit() and start: 
     business_hours.append({"weekday_name": current_day, "starting_time": start, "ending_time": entry}) 
     start = None 
    elif entry[0].isdigit(): 
     start = entry 

pprint.pprint(business_hours) 

Nadanie następujący wynik:

[{'ending_time': '5pm', 'starting_time': '10am', 'weekday_name': 'monday'}, 
{'ending_time': '9pm', 'starting_time': '6pm', 'weekday_name': 'monday'}, 
{'ending_time': '5pm', 'starting_time': '10am', 'weekday_name': 'tuesday'}, 
{'ending_time': '9pm', 'starting_time': '8am', 'weekday_name': 'sunday'}, 
{'ending_time': '1pm', 'starting_time': '10am', 'weekday_name': 'sunday'}, 
{'ending_time': '8pm', 'starting_time': '6pm', 'weekday_name': 'sunday'}]