Как преобразовать входные данные файла dumbo sequence в текст, разделенный табуляцией
Вопрос
У меня есть input, который может быть одним примитивом, списком или кортежем примитивов.
Я бы хотел свести его просто к списку, вот так:
def flatten(values):
return list(values)
Нормальным случаем было бы сгладить (someiterablethatisn'tastring)
Но если значения = '1234', я бы получил ['1', '2', '3', '4'], но я бы хотел ['1234']
И если значения = 1, я бы получил TypeError:объект 'int' не является итеративным, но я бы хотел [1]
Есть ли элегантный способ сделать это?Что я действительно хочу сделать в конце, так это просто '\ t'.join(сгладить(значения))
Редактировать:Позвольте мне объяснить это лучше...
Я хочу преобразовать файл двоичной последовательности hadoop в текстовый файл, разделенный плоскими табуляциями, используя dumbo.Используя опцию формат вывода, -outputformat текст
Dumbo - это оболочка python для потоковой передачи hadoop.Короче говоря, мне нужно написать функцию сопоставления:
def mapper (ключ, значения) # сделать что-нибудь выдать 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')
Входной ключ или значение может быть примитивом или списком / кортежем примитивов Я хотел бы функцию "flatten", которая может обрабатывать что угодно и возвращать список значений.
Для значения out я сделаю что-то вроде этого v = ' '.join(list(str(s) для s в flatten(seq)))
Решение
Звучит так, как будто ты хочешь 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))
Другие советы
Основываясь на вашем переформулированном вопросе, это 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
к a yield
.Это также предполагает, что ключом ввода всегда будет отдельный элемент или список элементов (не список списков) и что входные значения всегда будут списком элементов (опять же, не списком списков).
Соответствует ли это вашим требованиям?
Я должен сказать, что заявленные требования странны, и я не думаю, что расплющить это правильное название для такого рода операций.Но если ты действительно уверен, что это то, чего вы хотите, тогда это то, что я могу извлечь из вашего вопроса:
>>> 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'