2016-03-08 16 views
5

Mam dane 2D, do których chcę zastosować wiele funkcji. Rzeczywisty kod używa pliku xlrd i .xlsx, ale dostarczę następującą płytę kotła, dzięki czemu dane wyjściowe będą łatwe do odtworzenia.Zastosuj wiele funkcji na mapie

class Data: 
    def __init__(self, value): 
     self.value = value 

class Sheet: 
    def __init__(self, data): 
     self.data = [[Data(value) for value in row.split(',')] for row in data.split('\n')] 
     self.ncols = max(len(row) for row in self.data) 

    def col(self, index): 
     return [row[index] for row in self.data] 

Tworzenie arkusza:

fake_data = '''a, b, c, 
       1, 2, 3, 4 
       e, f, g, 
       5, 6, i, 
       , 6, , 
       , , , ''' 

sheet = Sheet(fake_data) 

W tym obiekcie, data zawiera 2D tablicę ciągów (za formatu wejściowego) i chcę, aby wykonywać operacje na kolumnach tego obiektu. Nic do tej pory nie jest pod moją kontrolą.

Chcę zrobić trzy rzeczy do tej struktury: transponuj wiersze do kolumn, wyodrębnijz każdego obiektu Data i spróbuj przekonwertować wartość na float. Jeśli wartość nie jest równa float, należy ją przekonwertować na str z usuniętą białą przestrzenią.

from operators import attrgetter 

# helper function 
def parse_value(value): 
    try: 
     return float(value) 
    except ValueError: 
     return str(value).strip() 

# transpose 
raw_cols = map(sheet.col, range(sheet.ncols)) 

# extract values 
value_cols = (map(attrgetter('value'), col) for col in raw_cols) 

# convert values 
typed_cols = (map(parse_value, col) for col in value_cols) 

# ['a', 1.0, 'e', 5.0, '', ''] 
# ['b', 2.0, 'f', 6.0, 6.0, ''] 
# ['c', 3.0, 'g', 'i', '', ''] 
# ['', 4.0, '', '', '', ''] 

Można zauważyć, że map jest stosowana do każdej kolumny dwukrotnie. W innych okolicznościach chcę zastosować funkcję do każdej kolumny więcej niż dwa razy.

Czy istnieje lepszy sposób odwzorowania wielu funkcji na wpisy w iteracji? Co więcej, czy jest tam, aby uniknąć zrozumienia generatora i bezpośrednio zastosować mapowanie do każdej wewnętrznej-iterowalnej? Czy istnieje lepszy i rozszerzalny sposób podejścia do tego wszystkiego?

Należy zauważyć, że to pytanie nie jest specyficzne dla xlrd, jest to tylko aktualny przypadek użycia.

+0

przypomnienia: 'mapy (m, mapy (g, nadmiar)) 'ma taką samą moc, jak' mapie (komponować (F, G), xs) '; pierwszy będzie dwukrotnie powtarzał kolekcję, ale drugi będzie tylko jeden raz. – naomik

+0

@naomik Dobrze, chciałbym tylko, żeby było wbudowane 'compose'. –

+1

Jared, z łatwością możesz zrobić własne. "compose" to nic innego jak "lambda f, g: lamda x: f (g (x))". Lub po prostu użyj 'map (lambda x: f (g (x)), xs)' – naomik

Odpowiedz

2

Wygląda na to, że najprostszym rozwiązaniem jest przeniesienie własnej funkcji, która zastosuje wiele funkcji do tej samej iteracji.

def map_many(iterable, function, *other): 
    if other: 
     return map_many(map(function, iterable), *other) 
    return map(function, iterable) 

Minusem jest to, że korzystanie jest odwrócona od map(function, iterable) i byłoby niewygodne przedłużyć map przyjąć argumentów (jak to możliwe w Pythona 3.X).

Zastosowanie:

map_many([0, 1, 2, 3, 4], str, lambda s: s + '0', int) 
# [0, 10, 20, 30, 40] 
4

Można łatwo klub dwa ostatnie map połączeń za pomocą lambda,

typed_cols = (map(lambda element:parse_value(element['value']), col) 
       for col in value_cols) 

ile można trzymać w podobny analizowania i wydobywania wewnątrz Sheet.col, IMO, które mogłyby wpłynąć na czytelność kodu.