ダンボシーケンスファイルの入力をタブ区切りテキストに変換する方法
質問
入力には、単一のプリミティブまたはプリミティブのリストまたはタプルがあります。
次のように、リストのみにフラット化したい:
def flatten(values):
return list(values)
通常の場合はフラット化されます(someiterablethatisn'tastring)
しかし、値= '1234'の場合、['1'、 '2'、 '3'、 '4']を取得しますが、['1234']が必要です
また、値= 1の場合、TypeErrorが発生します。「int」オブジェクトは反復可能ではありませんが、[1]が必要です
これを行うエレガントな方法はありますか? 最後に本当にやりたいことは、 '\ t'.join(flatten(values))
編集:これについて詳しく説明しましょう...
dumboを使用して、hadoopバイナリシーケンスファイルをフラットタブ区切りテキストファイルに変換したい。出力形式オプション-outputformat textを使用
Dumboは、HadoopストリーミングのPythonラッパーです。要するに、マッパー関数を書く必要があります:
def mapper(key、values) #何かをする 収量k、v
ここで、kはキーの最初の部分の文字列、valueはタブで区切られた文字列で、残りのキーと値を文字列として含みます。
eg:
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)))
解決
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
を yield
に変更したいようです。また、入力キーは常に単一のアイテムまたはアイテムのリスト(リストのリストではない)であり、入力値は常にアイテムのリスト(リストのリストではない)であると想定しています。
要件を満たしていますか?
記載されている要件は奇妙であると言わざるを得ず、 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'