2016-04-24 27 views
-2

私はPythonで任意にネストされたdictsのデカルト積を行うアルゴリズムを実装しました。ルートレベルにあるフィールドは、複数の行に複製する必要がありました。配列がネストされる可能性もあります。私はitertools.productを再帰的に使用し、中間イテレータを集約しました。動的に生成されたネストされたタプル

動作していますが、問題は最終段階でのアンパックです。 私はこのような構造になった:

(11, 12.2, 123.2, 1.23, 104.75, (10.7, 104.75, 104.75, ('N', True, False, 'B2B'), 99.01, 6.3, 1.23, 5.87, 12.2), 1, 'SP', 7)

私はリスト内包やジェネレータ式またはこの行を平らにし、きれいにすることができるにも本格的な発電機を探しています:

(11, 12.2, 123.2, 1.23, 104.75, 10.7, 104.75, 104.75, 'N', True, False, 'B2B', 99.01, 6.3, 1.23, 5.87, 12.2, 1, 'SP', 7)

これを実行する最善の方法は何ですか。私はitertools.productの出力を遮断する、フックに含める必要があるので、私はを求めてきたもの

実際にEDIT

は、リスト内包やジェネレータ式、あるいは本格的な発電です自体。これらのタプルをクリーニングするには、単にの方法が必要なわけではありません。したがってではありません。

皆さん、私はこのための再帰関数は欲しくありません! 私は、__iter__()メソッドが動的に生成されたデータのitertools.productを返すクラスを持っています。私はこれらのいずれかをしようとしている:変換を扱う別のオブジェクトに

class Explosion: 
    ... 
    def __iter__(self): 
     return product(*self.fragments) 
  • カプセル化が、これはあまり望ましい:

    1. は内部タプルを処理するために、このメソッドを変更

      class CleanOutput: 
          def __init__(self, it): 
           self.it = it 
      
          def next(self): 
           for x in self.it: 
            yield ? 
      
      class Explosion: 
          ... 
          def __iter__(self): 
           return CleanOutput(product(*self.fragments)) 
      
  • +0

    あなたはどのようにあなたが最初に達成することをあなたのコードを表示することができます結果? – Kasramvd

    +0

    申し訳ありません@Kasramvd、私はできません。しかし、それほど複雑ではありません。単純な_flatten dict_アルゴリズムです。シーケンスが手元にあるときを検出し、その要素を取得して試してみて、プリミティブであれば使用するitertools.productでは、ネストされたdictの場合、エントリごとにルートオブジェクトのような別の爆発オブジェクトを作成する必要があるため、難しくなります。次に、リストを連結してこれらの製品(ネストされたタプル)を結合し、これに外部製品を適用します。 – rsalmei

    +0

    正直言って、私はあなたがリンクされたページから最高の投票回答を使用するのを止めているのか分かりません。 'product'は反復子を返します。これは関数に送られ、' return flatten(product(...) 'のような結果ジェネレータを返します。 – vaultah

    答えて

    0
    def gen(data): 
        for item in data: 
         if isinstance(item, tuple): 
          for nested in gen(item): 
           yield nested 
         else: 
          yield item 
    

    Untesteしかし、うまくいくはずです。

    +0

    いいえ、ありがとうございます。 itertools.product()は、タプルを異なる組み合わせとして返します。これらの組み合わせは、内側のタプルを除いてしか使用しないでください。これで、私が得たのは、組み合わせの境界なしに、数十の別々のintまたは文字列でした。 – rsalmei

    +0

    @rsalmeiだから、発電機が必要ないと言っているのですか? – Natecat

    +0

    いいえ、私は発電機が欲しいです!それは私が求めていることです:リストの理解やジェネレータの表現...私は、組み合わせではなく内側のタプルを削除するだけです。 – rsalmei

    1

    これは簡単ではありませんが、再帰を使用する必要がありますが、メインの__iter__メソッドから分離してください。それが私のやり方です。 は今も、別の発電機_flattenによって呼び出される再帰発電_merge、と:

    class Explosion: 
        # ... 
    
        def __iter__(self): 
         def _flatten(container): 
          def _merge(t): 
           for te in t: 
            if isinstance(te, tuple): 
             for ite in _merge(te): 
              yield ite 
            else: 
             yield te 
    
          for t in container: 
           yield tuple(_merge(t)) 
    
         return _flatten(product(*self.fragments)) 
    

    _flatten()機能の利用の例を参照してください:

    >>> list(itertools.product([1,2],[3,(4,(5,6))])) 
    [(1, 3), (1, (4, (5, 6))), (2, 3), (2, (4, (5, 6)))] 
    >>> list(_flatten(itertools.product([1,2],[3,(4,(5,6))]))) 
    [(1, 3), (1, 4, 5, 6), (2, 3), (2, 4, 5, 6)] 
    
    +1

    もし必要ならば、あなたは '_flatten'ヘルパメソッド*をあなたの' __iter__'メソッドの中に入れ子にすることもできますどこか他の。 –

    +0

    それはクールです@ビーコマンドン、ありがとう! – rsalmei

    +0

    @ByteCommander、私は 'merge'ヘルパーメソッドを_flattenジェネレータ内の2番目のジェネレータにしようとしましたが、動作しません。外部タプル(維持したいタプル)が空になりました。なぜなのかご存知ですか?私は多量のデータを移動するために一時シーケンスを使用するのではなく、... – rsalmei

    関連する問題