1

itertools.product と同じように機能する関数が必要ですが、項目を繰り返さないでください。

例えば:

no_repeat_product((1,2,3), (5,6))
= ((1,5), (None,6), (2,5), (None,6), ...(None,6))
no_repeat_product((1,2,3), (5,6), (7,8))
= ((1,5,7), (None,None,8), (None,6,7), (None,None,8), ...(None,None,8))

何か案は?

編集:私の言い回しは正しくありませんでした。連続する出力値で同じ数値を繰り返さないことを意味しました。
例えば、

itertools.product((1,2,3), (4,5), (6,7) is
(1,4,6)
(1,4,7), etc  

ここでは、出力に 1,4 が 2 回表示されます。なので、前の項目と同じ数字の場合は省略したいと思います。したがって、私が望む出力は次のとおりです。

(1,4,6)  
(None,None,7)  

None の場合は、結果の前の項目と同じであることがわかります。

さらに編集:

私の説明はまだはっきりしていませんでした。本、章番号、ページ番号のリストがあるとします。各本には同じ数の章があり、各章には同じ数のページがあると仮定します。したがって、リストは (book1, book2, book3), (chap1, chap2), (page1, page2, page3) です。
ここで、各ページの説明を収集したいとします:
itertools.product は以下を提供します:

(book1, chap1, page1), (book1, chap1, page2)..... (book3, chap2, page3)

これらのページを連続して配置した場合、説明を繰り返す必要はありません。したがって、本と章が同じ場合、2 ページ目には本と章の名前は必要ありません。出力は次のようになります。

(book1, chap1, page1), (None, None, page2), ..   
(when the pages of first chapter are over..) (None, chap2, page1), (None, None, page2)......  
(when the chapters of the first book are over..)(book2, chap1, page1)..............  
(None, None, page3)  
4

3 に答える 3

2
def no_repeat_product(*seq):
    def no_repeat(x, known):
        if x in known:
            return None
        else:
            known.add(x)
            return x

    known = set()
    for vals in itertools.product(*seq):
        yield tuple(no_repeat(x, known) for x in vals)

これは、以前に見られた値を返しません。これは、あなたの望むことですか?

前の結果セットに表示された値の繰り返しのみを制限したい場合は、次の方法で実行できます。

def no_repeat_product(*seq):
    prev = None
    for vals in itertools.product(*seq):
        if prev is None:
            yield vals
        else:
            yield tuple((x if x != y else None) for x, y in zip(vals, prev))
        prev = vals
于 2011-06-03T08:53:47.750 に答える
2

ティーイテレーターを使用した、@ShawnChinの回答の機能バージョンの並べ替え:

from itertools import product,tee,izip
def product_without_repeats(*seq):
    previter,curriter = tee(product(*seq))
    try:
        yield next(curriter)
    except StopIteration:
        pass
    else:
        for prev,curr in izip(previter,curriter):
            yield tuple(y if x!=y else None for x,y in izip(prev,curr))
于 2012-08-13T10:17:17.233 に答える
2

「(None、None、8)が連続して発生しないため」というコメントに基づいて、直前の出力に表示される要素のみをNoneにしたいと仮定しています。

def no_repeat_product(*seq):
    previous = (None,)*len(seq)
    for vals in itertools.product(*seq):
        out = list(vals)
        for i,x in enumerate(out):
            if previous[i] == x:
                out[i] = None
        previous = vals
        yield(tuple(out))   

または、よりコンパクトで効率的な (ただし読みにくい) バージョンが必要な場合は、次のようにします。

def no_repeat_product(*seq):
    previous = (None,)*len(seq)
    for vals in itertools.product(*seq):
        out = tuple((y,None)[x==y] for x,y in itertools.izip(previous, vals))
        previous = vals
        yield(out)       

どちらも同じことを行い、次の結果を生成します。

for x in no_repeat_product((1,2,3), (5,6), (7,8)): 
    print x 

出力:

(1, 5, 7)
(None, None, 8)
(None, 6, 7)
(None, None, 8)
(2, 5, 7)
(None, None, 8)
(None, 6, 7)
(None, None, 8)
(3, 5, 7)
(None, None, 8)
(None, 6, 7)
(None, None, 8)

更新された質問のコンテキストでの例:

books = ("Book 1", "Book 2")
chapters = ("Chapter 1", "Chapter 2")
pages = ("Page 1", "Page 2", "Page 3")

s1 = max(map(len, books)) + 2  # size of col 1
s2 = max(map(len, chapters)) + 2  # size of col 2
x = lambda s, L: (s, "")[s == None].ljust(L)  # Left justify, handle None

for book, chapter, page in no_repeat_product(books, chapters, pages):
    print x(book, s1), x(chapter, s2), page

これにより、以下が得られます。

Book 1   Chapter 1   Page 1
                     Page 2
                     Page 3
         Chapter 2   Page 1
                     Page 2
                     Page 3
Book 2   Chapter 1   Page 1
                     Page 2
                     Page 3
         Chapter 2   Page 1
                     Page 2
                     Page 3
于 2011-06-03T09:10:24.037 に答える