2016-03-22 16 views
1

ネストされたリストを取り、一意の要素のセットを返す再帰関数(簡単のため)を作成する必要があります。これを取り組むためにネストされたリストを再帰関数を使ってセットに変換する

が、私は最初のリストを受け取り、セットに変換する関数を作成することにしました:十分な

ranList = [2, 2, 4, 5, 3, 1, 3] 

def eue(ranList): 
    newList = set(ranList) 
    return print(newList) 

は簡単、それが動作します。今度はネストされたリストを受け取り、2-Dリスト(これはこのサイトで検索を使用して見つけた再帰関数です)と他の関数を取り、固有の要素を含むセットを返す関数を作成します:

lis = [['c', 'd'], 2, 2, 4, 5, 3, 1, 3, ['c']] 

from collections import Iterable 

def flatten(lis): 
    for item in lis: 
     if isinstance(item, Iterable) and not isinstance(item, str): 
      for x in flatten(item): 
       yield x 
     else:   
      yield item 

def eue(lis): 
    newSet = set(flatten(lis)) 
    print(newSet) 

今、eue()を呼び出して、私の元の質問を解決します。しかし私はもっと単純化したいと思っています。

これらの関数を組み合わせて、実行に要する計算時間を削減する単一の関数を作成するにはどうすればよいですか?

ありがとうございました。

+3

元の 'flatten'はジェネレータなので、それを単一の関数にまとめることで大幅なスピードアップになることはまずありません。これがプログラムの重要なボトルネックでない限り、私はおそらくこれを最適化しようとすることについて心配しないでしょう... – mgilson

+3

あなたの関数 'eue'にはNoneが返されます –

+1

@PadraicCunningham、ありがとうそれに気付く。私はできるだけ早くそれを修正します。 –

答えて

1

あなたはすべてのイテレータを一緒にリンクするitertools.chainを使用することができます。

from itertools import chain 
from collections import Iterable 

def isIter(obj): 
    return isinstance(obj, Iterable) and not isinstance(obj,str) 
def flatten(it): 
    seqs = (flatten(item) if isIter(item) else (item,) for item in it) 
    return chain(*seqs) 
def enu1(it): 
    return set(gen(it)) 

これは、すべての非シーケンスの要素のためにあなたが適切に動作するチェーンのための1つのアイテム(item,)でタプルをしなければならないことを意味しますが、ありませんそれがパフォーマンスにどのくらいの影響を与えるかを確かめてください。

あなたはセットに変換して(他のその後isIter)単一の関数にこれを減らすことができます。

def enu2_A(it): 
    seqs = (enu2_A(item) if isIter(item) else (item,) for item in it) 
    return set(chain(*seqs)) 

をしかし、再び、これはenuへのすべての再帰呼び出しのための新しいsetオブジェクトを作成し、多分にオプションを追加変換する?

def enu2(it,return_set = True): 
    seqs = (enu2(item,False) if isIter(item) else (item,) for item in it) 
    if return_set: 
     return set(chain(*seqs)) 
    else: 
     return chain(*seqs) 

が、単一の関数にそれを組み合わせることが本当にすべてであまりスピードブーストを与えるものではありません:

import timeit 

a = timeit.timeit("enu1(lis)","from __main__ import enu1,lis",number=10000) 
b = timeit.timeit("enu2(lis)","from __main__ import enu2,lis",number=10000) 

print(a,b) 
print(a/b) #ratio, more then 1 means a took longer 

出力:単一に組み合わせることにより、その3%速く

0.3400449920009123 0.32908301999850664 
1.0333106582115827 

私はそれがあなたが期待していたスピードアップではなかったと推測しています。あなたのコードは非常に効率的です。


EDIT:ちょうど私のenu2のベンチマークを行なったし、あなたのenu - あなたの方法は、より速く、私は16%程度によって提供されている1、その後、あなたがあまり良く得ることができないとして、それがあるとして、それを残しています他は、その後python2に移動しcompiler.ast.flattenまたは別のCレベルequivelentを使用して:

from collections import Iterable 

def flatten(lis): 
    for item in lis: 
     if isinstance(item, Iterable) and not isinstance(item, str): 
      for x in flatten(item): 
       yield x 
     else:   
      yield item 

def enu(obj): 
    return set(flatten(obj)) 

lis = [['c', 'd'], 2, 2, 4, 5, 3, 1, 3, ['c']] 

import timeit 

a = timeit.timeit("enu(lis)","from __main__ import enu,lis",number=10000) 

b = timeit.timeit("set(ast.flatten(lis))","from __main__ import lis ; from compiler import ast",number=10000) 

print(a,b) 
print(a/b) 

出力:

0.3324121500045294 0.28561264199379366 
1.1638565705076622 

のようになりました.Cでの操作を実行すると、プロセスが4倍高速化されましたが、compilerパッケージは2以降は古くなっています。6 the docsによると:

バージョン2.6で撤廃

:コンパイラパッケージは、Python 3に

を削除されているので、あなたがCの拡張機能でflattenを書いた場合、あなたも得ることができるということは十分に可能ですより良い結果が得られますが、純粋なPythonでコードを記述したい場合は、あなたが得ることができる程度に優れています。

関連する問題