如何将dumbo序列文件输入转换为制表符分隔文本

时间:2009-10-26 16:26:46

标签: python text hadoop

我有输入,可以是单个基元或基元的列表或元组。

我想把它变成一个列表,就像这样:

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)))

3 个答案:

答案 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'