我有输入,可以是单个基元或基元的列表或元组。
我想把它变成一个列表,就像这样:
def flatten(values):
return list(values)
正常情况会变平(有些人可能不会串行)
但如果值='1234',我会得到['1','2','3','4'],但我想要['1234']
如果values = 1,我会得到TypeError:'int'对象不可迭代,但我想要[1]
有优雅的方法吗? 我最终想要做的只是'\ t'。join(flatten(values))
编辑:让我更好地解释一下......
我希望使用dumbo将hadoop二进制序列文件转换为平面制表符分隔文本文件。使用输出格式选项-outputformat text
Dumbo是围绕hadoop流的python包装器。总之我需要编写mapper函数:
def mapper(键,值) #do一些东西 产量k,v
其中k是键中第一部分的字符串,value是一个制表符分隔的字符串,其中包含键的其余部分,值为字符串。
例如:
input: (123, [1,2,3])
output: ('123', '1\t2\t\t3')
或更复杂:
input: ([123, 'abc'], [1,2,3])
output: ('123', 'abc\t1\t2\t\t3')
输入键或值可以是基元或基元的列表/元组 我想要一个可以处理任何事情的“扁平”函数,并返回一个值列表。
对于out值,我会做这样的事情 v ='\ t'。join(list(str(s)for s in flatten(seq)))
答案 0 :(得分:3)
听起来像你想要itertools.chain()
。但是,您需要特殊情况的字符串,因为它们实际上只是字符的迭代。
<强>更新强>:
如果将其作为递归生成器,这是一个更简单的问题。试试这个:
def flatten(*seq):
for item in seq:
if isinstance(item, basestring):
yield item
else:
try:
it = iter(item)
except TypeError:
yield item
it = None
if it is not None:
for obj in flatten(it):
yield obj
这会返回一个迭代器而不是一个列表,但是它被懒惰地评估了,这可能是你想要的。如果您确实需要列表,请改用list(flatten(seq))
。
更新2 :
正如其他人所指出的那样,如果你真正想要的是将它传递给str.join()
,那么你需要将所有元素转换为字符串。为此,您可以在上面的示例中将yield foo
替换为yield str(foo)
,或者只使用以下代码:
"\t".join(str(o) for o in flatten(seq))
答案 1 :(得分:1)
根据您重申的问题,此mapper
函数可能会执行您想要的操作:
def mapper(key, values):
r"""Specification: do some stuff yield k, v where k is a string from the
first part in the key, and value is a tab separated string containing the
rest of the key and the values as strings.
>>> mapper(123, [1,2,3])
('123', '1\t2\t3')
>>> mapper([123, 'abc'], [1,2,3])
('123', 'abc\t1\t2\t3')
"""
if not isinstance(key, list):
key = [key]
k, v = key[0], key[1:]
v.extend(values)
return str(k), '\t'.join(map(str, v))
if __name__ == '__main__':
import doctest
doctest.testmod()
您可能希望将return
更改为yield
。这也假定输入键将始终是单个项目或项目列表(不是列表列表),并且输入值将始终是项目列表(同样,不是列表列表)。
这符合您的要求吗?
答案 2 :(得分:0)
我必须说明的要求是奇怪的,我不认为 flatten 是这种操作的正确名称。但如果你真的确定这是你想要的,那么这就是我可以从你的问题中提炼出来的:
>>> import itertools
>>> def to_list_of_strings(input):
... if isinstance(input, basestring): # In Py3k: isinstance(input, str)
... return [input]
... try:
... return itertools.chain(*map(to_list_of_strings, input))
... except TypeError:
... return [str(input)]
...
>>> '\t'.join(to_list_of_strings(8))
'8'
>>> '\t'.join(to_list_of_strings((1, 2)))
'1\t2'
>>> '\t'.join(to_list_of_strings("test"))
'test'
>>> '\t'.join(to_list_of_strings(["test", "test2"]))
'test\ttest2'
>>> '\t'.join(to_list_of_strings(range(4)))
'0\t1\t2\t3'
>>> '\t'.join(to_list_of_strings([1, 2, (3, 4)]))
'1\t2\t3\t4'