0

入力があります。これは、単一のプリミティブ、またはプリミティブのリストまたはタプルである可能性があります。

次のように、リストにまとめたいと思います。

def flatten(values):
    return list(values)

通常の場合はフラットになります(tastringではない)

しかし、values = '1234'の場合、['1'、 '2'、 '3'、 '4']を取得しますが、['1234']が必要です。

そして、values = 1の場合、TypeErrorが発生します。'int'オブジェクトは反復可能ではありませんが、[1]が必要です。

これを行うためのエレガントな方法はありますか?最後に本当にやりたいのは'\t'.join(flatten(values))

編集:これをもっとよく説明させてください...

ダンボを使用して、Hadoopバイナリシーケンスファイルをフラットタブで区切られたテキストファイルに変換したいと思います。出力フォーマットオプションを使用して、-outputformat text

Dumboは、HadoopストリーミングのPythonラッパーです。要するに、私はマッパー関数を書く必要があります:

def mapper(key、values)#いくつかのことを行うyield 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)))

4

3 に答える 3

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 fooyield str(foo)次のようなコードを使用します。

"\t".join(str(o) for o in flatten(seq))
于 2009-10-26T16:32:09.537 に答える
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()

おそらくそれをに変更したいと思うでしょreturnyield。また、これは、入力キーが常に単一の項目または項目のリスト (リストのリストではない) であり、入力値が常に項目のリスト (リストのリストではない) であることも前提としています。

それはあなたの要件を満たしていますか?

于 2009-10-26T19:52:46.260 に答える
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'
于 2009-10-26T16:45:36.623 に答える