2016-03-08 9 views
5

複数の関数を適用したい2Dデータがあります。実際のコードはxlrd.xlsxファイルを使用していますが、出力を再現しやすいように次のボイラープレートを用意します。 dataは、(入力フォーマットごとに)文字列の2次元アレイを含み、このオブジェクトのマップで複数の関数を適用する

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

sheet = Sheet(fake_data) 

と私は、このオブジェクトの列に対して操作を実行する:

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] 

シートを作成します。これまでのことは私のコントロール下にありません。

私は、この構造体に3つのことをやりたい:、列に行を転置各Dataオブジェクトからvalueを抽出し、floatに値を変換してみてください。値がfloatでない場合は、空白を取り除いてstrに変換する必要があります。

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, '', '', '', ''] 

mapは二回、各列に適用されていることが分かります。他の状況では、2回以上各列に関数を適用したいと考えています。

イテラブルのエントリに複数の関数をマップする方が良いですか?さらに、ジェネレータの理解を避け、それぞれの内部反復可能なものへのマッピングを直接適用することができますか?あるいは、これをすべて一緒に近づけるためのより良い拡張可能な方法がありますか?

この質問は、xlrdに固有のものではなく、現在のユースケースのみです。

+0

リマインダー: 'マップ(F、マップ(G、Xは))' ''マップ((F、Gを構成する)、XS)と同じ出力を有します。前者はコレクションを2回繰り返しますが、後者は1回のみ繰り返します。 – naomik

+0

@naomik右のように、私が思うに 'compose'組み込みがあったといいですね。 –

+1

ジャレド、あなたは簡単にあなた自身を作ることができます。 'compose'は' lambda f、g:lamda x:f(g(x)) 'にすぎません。あるいは 'map(lambda x:f(g(x))、xs)' – naomik

答えて

2

最も簡単な解決策は、複数の機能を同じ繰り返し可能性に適用する独自の機能をロールすることです。ここ

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

欠点は、使用量がmap(function, iterable)から逆転され、(Pythonの3.Xでそれができるように)引数を受け入れるようにmapを拡張しにくいだろうということです。

使用:

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

あなたは簡単にクラブlambda

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

を使用して、最後の2つのmap呼び出しはあなたがSheet.col内で抽出、IMOコードの可読性を同様の解析でスティックに影響を与えることができますが。

関連する問題