dumbo 시퀀스 파일 입력을 탭으로 구분된 텍스트로 변환하는 방법
문제
단일 기본 요소 또는 기본 요소의 목록 또는 튜플이 입력될 수 있습니다.
다음과 같이 목록으로 정리하고 싶습니다.
def flatten(values):
return list(values)
일반적인 경우는 평평해질 것입니다.
그러나 값 = '1234'이면 ['1', '2', '3', '4']를 얻지만 ['1234']를 원합니다.
값이 1이면 TypeError가 발생합니다.'int' 객체는 반복 가능하지 않지만 [1]을 원합니다.
이를 수행하는 우아한 방법이 있습니까?결국 내가 정말로 하고 싶은 것은 ' '.join(Flatten(values)) 입니다.
편집하다:이것을 더 잘 설명하자면...
dumbo를 사용하여 hadoop 바이너리 시퀀스 파일을 플랫 탭으로 구분된 텍스트 파일로 변환하고 싶습니다.출력 형식 옵션인 -outputformat text 사용
Dumbo는 hadoop 스트리밍을 둘러싼 Python 래퍼입니다.간단히 말해서 매퍼 함수를 작성해야 합니다.
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')
입력 키 또는 값은 프리미티브 또는 프리미티브의 목록/튜플 일 수 있습니다. 나는 무엇이든 처리 할 수 있고 값 목록을 반환 할 수있는 "평평한"함수를 원합니다.
아웃 값을 위해, 나는이 v = ' t'.join과 같은 일을 할 것이다 (평평한 s에 대한 str (s)).
해결책
당신이 원하는 것 같네요 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'