0

Hi I have a generator object. I want to count how many of each element there are in it. Without destroying the generator/changing (i want to use it again later).

Here is an example.

def create(n):
    items = ["a", "b", "c"]
    for i in range(n):
        yield items[random.randint(0,2)]

def countEach(gen):
    r = []
    for a in gen:
        add = True
        for i in range(len(r)):
            if a == r[i][0]:
                r[i][1] += 1
                add = False
        if add:
            r.append([a,0])
    return r

gen_list = create(100)
print (countEach(gen_list))
for b in gen_list:
    print (b)

output

[['b', 33345], ['c', 33298], ['a', 33354]]
[Finished in 0.6s]
8
  • Not possible without creating a permanent data structure, like a list. Commented Jan 23, 2019 at 6:17
  • I noticed that when using yield code after is also executed. Is it possible to yield and return somehow? Commented Jan 23, 2019 at 6:20
  • You could also use itertools.tee to make n independent iterators from a single iterable. Commented Jan 23, 2019 at 6:21
  • You could append to a list, then return it at the end, but you can't mix return and yield. But list(create(100)) will do the job much easier. You can reuse this list as much as you want. Commented Jan 23, 2019 at 6:21
  • @AbdulNiyasPM But the resulting iterators may yield different values. Commented Jan 23, 2019 at 6:22

2 Answers 2

1

Unless I am fundamentally misunderstanding how Python generators work, this isn't possible and you should return in your create method rather than yield a generator.

def create(n):
    items = ["a", "b", "c"]
    return [items[random.randint(0,2)] for i in range(n)]

The above list comprehension will create a list rather than use a generator. For a better understanding of generators I'd suggest reading through this excellent post.

EDIT: Out of curiosity I timed the list(create(n)) method suggested by Tomothy32 against mine which returns a list. As expected, it's marginally slower to return the generator then store the list via comprehension (averaged 130 microseconds vs 125 microseconds). However you may prefer to leave the original method untouched and have the simple option of saving specific generator calls as lists rather than redefining it and always returning a list object.

Sign up to request clarification or add additional context in comments.

Comments

0

There is no need to change the create generator. Just do:

gen_list = list(create(100))

You can reuse this as much as you want.

2 Comments

I know i can make a list of it. But if i have a bigger list I will get a memory error.
@Staked In that case, I apologize, but it is impossible. See stackoverflow.com/questions/3345785/…

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.