Python迭代器类-嵌套迭代

Python迭代器类-嵌套迭代,python,iterator,itertools,Python,Iterator,Itertools,假设我想创建一个迭代器类,它接受另一个迭代器作为输入,并计算元素的频率。我不能使用列表、dict或任何其他数据结构将多个元素的信息存储在一起,所以我必须通过创建某种嵌套迭代来解决这个问题。从概念上讲,我希望我的类执行以下操作: for i in iter(input): count=0 for j in iter(input): if i=j: count+=1 if j = None:

假设我想创建一个迭代器类,它接受另一个迭代器作为输入,并计算元素的频率。我不能使用列表、dict或任何其他数据结构将多个元素的信息存储在一起,所以我必须通过创建某种嵌套迭代来解决这个问题。从概念上讲,我希望我的类执行以下操作:

for i in iter(input):
        count=0
        for j in iter(input):
            if i=j:
               count+=1
            if j = None: #iterator is done
               # reset j
               # move to next element of i
在很多方面,这显然是一个简化的示例,但我希望我的类的总体预期结构是清楚的。每次我都会将I的值和计数保存到磁盘,但现在我们可以忽略它

我遇到的第一个问题是Python不允许迭代器在使用后重置,这就产生了重置内部循环j的问题。我在启动第二个迭代器时使用itertools.cycle克服了这一问题,该迭代器允许无休止的迭代。不幸的是,我下面的代码只对数据进行了一次成功传递,第一个if语句不返回外部迭代器的下一个值,而是将其视为已被使用


class Match:

    def __init__(self, input):
        '''
        Input is an iterator
        '''
        self.in1 = input 
        self.in2 = input
        self.c=0 #the count

    def __iter__(self):
        '''
        Initializes the iterators and fetches the first element
        '''

        self.it1 = iter(self.in1) # initialize the first (outer) iterator
        self.it2 = itertools.cycle(iter(self.in2)) # initialize the second (inner) iterator

        self.i = next(self.it1) #pin the first elements
        self.j = next(self.it2)

        return self

    def _inc_outter_end(self): 
        '''increment or end outer iterator'''
        try:
            self.i = next(self.it1)
        except StopIteration:
            self.i = None
            self.j = None


    def __next__(self):

        i = self.i
        j = self.j
        self.j = next(self.it2) 
        self.c+=1

        if self.c ==9:
            self.c=0
            self._inc_outter_end()      
            i = self.i 

        #stop if done
        elif i == None:
            raise StopIteration()

        #skip non-pairs
        elif i != j:
            return self.__next__()
        #count and return matches
        elif i==j:
            return self.c
运行类似于:

i1 = [1,7,2,4,6,6,1,1,3]
for match in Match(iter(i1)):
    print(match)
一次传递数据,使i始终为1,而不是对输入停止的所有下一个元素再进行8次传递。相反,我希望它返回与以下相同的输出:

i1 = [1,7,2,4,6,6,1,1,3]
for i in i1:
    count=0
    for j in i1:
        if i==j:
            count+=1
    print(i,count)
给予

1 3
7 1
2 1
4 1
6 2
6 2
1 3
1 3
3 1

看起来,对于输入迭代器中的每个元素,您都希望发出整个迭代器生成该元素的次数。显然,在完全耗尽迭代器之前,无法计算该数字。这意味着,无论您提出什么解决方案,它都必须以某种方式存储有关迭代器元素的一些信息,这样所有元素的信息都会同时存储

但是你也说

我不能使用列表、命令或其他任何东西[…]

现在还不清楚你的具体意思是什么,其他任何东西到底指的是什么?但人们可能会自然而然地认为,你可以用来同时存储关于迭代器所有元素的信息的任何东西都是禁止的。如果这是你的情况,那么这项任务是不可能的。你必须放松你的一个限制,或者找到一种方法来解决这个问题

如果我在这里发布的内容不是针对您的情况对列表、口述或其他任何内容的正确解释,那么您必须澄清您的意思,也许更清楚地说明解决方案


有人可能会提出反对意见,你可以这样做,这基本上是复制一个迭代器,让你在它上面迭代两次或多次。但是tee的底层实现实际上相当于将迭代器的内容存储在列表中,我假设您的条件排除了这一点。tee实际上比列表更有效,因为如果您的使用模式允许,它只能存储迭代器的一部分,而不能存储整个迭代器。但事实并非如此;您尝试执行的任务需要存储有关整个迭代器的信息。

以下是一种仅使用迭代器就可以计算列表中元素的方法。这将为每个元素打印一个计数,而不是重复重复元素的计数。如果你真的需要以另一种方式报告,也许这会给你一个想法

基本计划是通过元素循环并计算目标(如果匹配)。如果它们不匹配,则返回元素。countFirst函数既是计数器又是生成器,提供非目标值:

def countTarget(it, target):
    count = 1
    for i in it:
        if i == target:
            count += 1
        else:
            yield i
    print(f"number: {target} count: {count}")

def count(it):
    while True:      
        try:
            target = next(it)
        except StopIteration:
            return
        it = countTarget(it, target)


orig = iter([1,7,2,4,6,6,1,1,3])

count(orig)
印刷品:

number: 1 count: 3
number: 7 count: 1
number: 2 count: 1
number: 4 count: 1
number: 6 count: 2
number: 3 count: 1

当然,这并不是特别有效——对于每个唯一的值,您在迭代器上循环一次。但这似乎更像是一个全面的练习,而不是一个实际的练习

计算元素频率似乎不像迭代器的工作。要做到这一点,您需要完全使用输入,在这一点上,您还可以构建并返回计数的映射。还不清楚“递归地解决这个问题-即通过创建嵌套迭代”是什么意思。一般来说,迭代和递归不是一回事。@MarkMeyer,谢谢你指出这一点!我的确切意思是,我正在寻找一种解决方案,它不断迭代输入,直到用尽所有可能的组合。递归确实不是一个正确的词,我为混淆道歉。您希望最后一个代码示例打印什么?我们需要查看您作业的确切文本。我们可能缺少一些重要的上下文。谢谢你的输入David!你对我不能使用的结构的解释是完全正确的——任何可以用来同时存储关于多个元素的信息的东西都是禁止的。我完全理解这是一个非常奇怪的情况,虽然没有单一的原因可以解释为什么我不能使用这些结构中的任何一个,让我们说我正在尝试
g以更好地理解迭代器。您提到该任务是不可能的——但是,上面的嵌套循环实现提供了所需的输出。我正在寻找一种用迭代器实现的方法。在这种情况下,我必须坚持我的答案,即迭代器无法实现这一点。这个答案隐藏了调用堆栈中的存储—一个堆栈帧用于记录每个唯一的输入值。它可能满足最初的任务要求,我们仍然不知道最初的要求,但它不能避免具体化输入的需要。我不确定我是否同意@user2357112supportsMonica,但也许通过bebugger运行它会说服我。这只会创建延迟计算的迭代器,因此数据永远不会被复制。它只是以类似于协同程序的方式通过管道。这只是链接迭代器。链的深度与输入中不同元素的数量一样,每个生成器记录一个元素。对于具有n个不同元素的输入,将创建n个生成器,其中n个目标变量包含n个不同元素和其他每个生成器开销的n个副本。筑巢也意味着这一点。好吧,这很有说服力。谢谢@user2357112supportsMonica。我将留下这个答案,以防它对操作有用。@MarkMeyer谢谢你的答案,非常感谢!看起来确实没有办法用上面提到的Python中的迭代器做到这一点,但它仍然很有用。