我有2D数据,我想要应用多个功能。实际代码使用xlrd
和.xlsx
文件,但我会提供以下样板,以便输出易于重现。
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]
创建工作表:
fake_data = '''a, b, c,
1, 2, 3, 4
e, f, g,
5, 6, i,
, 6, ,
, , , '''
sheet = Sheet(fake_data)
在此对象中,data
包含一个二维字符串数组(按照输入格式),我想对该对象的列执行操作。到目前为止,我无法控制任何事情。
我想对此结构做三件事:将行转换为列,从每个value
对象中提取Data
,然后尝试将值转换为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
两次应用于每列。在其他情况下,我想将一个函数应用于每列两次以上。
是否有更好的方法将多个函数映射到iterable的条目?更重要的是,有没有避免生成器理解并直接将映射应用于每个内部可迭代?或者,有没有更好和可扩展的方法来解决这个问题?
请注意,此问题并非特定于xlrd
,它只是当前的用例。
答案 0 :(得分:6)
似乎最简单的解决方案是滚动自己的函数,将多个函数应用于同一个迭代函数。
def map_many(iterable, function, *other):
if other:
return map_many(map(function, iterable), *other)
return map(function, iterable)
这里的缺点是用法与map(function, iterable)
相反,将map
扩展为接受参数(如Python 3.X中的那样)会很尴尬。
用法:
map_many([0, 1, 2, 3, 4], str, lambda s: s + '0', int)
# [0, 10, 20, 30, 40]
答案 1 :(得分:4)
您可以使用map
,
lambda
来电
typed_cols = (map(lambda element:parse_value(element['value']), col)
for col in value_cols)
虽然你可以在Sheet.col
内解析和提取内容,但会影响代码的可读性。