Print out n elements of a list each time a function is run

Viewed 840

I have a list of strings and I need to create a function that prints out n elements of the list each time it is run. For instance:

book1 = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o']

Expected output first time I run the function if n = 5:

a
b
c
d
e

second time:

f
g
h
i
j

I tried this:

def print_book(book):
    printed = book
    while printed != []:
        for i in range(0, len(book), 5):
            new_list = (book[i:i+5])
            for el in new_list:
                print(el)
        break
    del(printed[i:i+10])

And I get either the entire list printed out, or I end up printing first n elements each time I run the function. If this question has already been asked, please point it out to me, I would really apreciate it. Thanks!

7 Answers

A common approach is a generator expression. A generator expression yields it value when it is needed and hence, the whole list would not be created at once

A solution to your problem might be this

book1 = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o']

def yield_book(book1):
    for i in book1:
        yield i;
                
def print_n_item(gen, n):
    count = 0
    for i in gen:
        if count == n:
            return
        print(i)
        count += 1
        
gen = yield_book(book1)
print_n_item(gen, 5) # prints a,  b,  c, d, e
print_n_item(gen, 5) # prints f,  g,  h,  i,  j
print_n_item(gen, 5) # prints k,  l,  m,  n,  o

This approach exhausts the iterator and hence can be used once, in order to iterate again, you have to call yield_book to return a new generator

I guess you can try the following user function which applied to iterator book

def print_book(book):
    cnt = 0
    while cnt < 5:
        try:
            print(next(book))
        except StopIteration:
            print("You have reached the end!")
            break
        cnt += 1

such that

>>> bk1 = iter(book1)
>>> print_book(bk1)
a
b
c
d
e
>>> print_book(bk1)
f
g
h
i
j
>>> print_book(bk1)
k
l
m
n
o
>>> print_book(bk1)
You have reached the end!

As mentioned in a comment, you really want to encapsulate the state in some kind of data structure. The class approach:

class Printer:
    def __init__(self, book, n=5):
        self.book = book
        self.index = 0
        self.n = n

    def print(self):
        index = self.index
        self.index += self.n
        for t in self.book[index:self.index]:
            print(t)


book1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o']
printer = Printer(book1)
printer.print()
print()
printer.print()

Result:

a
b
c
d
e

f
g
h
i
j

You can define a specific function, taking advantage of the behavior of a mutable default argument in a function (you can use as a memory of the function):

book1 = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o']
    
def print_books(n, i=[0]):
    list(map(print, book1[i[0]:i[0] + n]))
    i[0] = (i[0] + n) if i[0] < len(book1) else 0

print_books(5)
print()
print_books(5)

n is the number of the items of the list to print and it is reset to 0 once the end of the list is reached; i is a list used to store the index of the first element not printed yet.

You should avoid this feature because it can generate strange and unexpected behaviors (take a look here), but it can be used to save the state of a function and I thought it worths a mention here.

And as a function factory

book_1 = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o']

def printer_factory(book, n = 5):
    i = 0
    def printer():
        nonlocal i
        stop = min(i+n, len(book))
        while i < stop:
            print(book[i])
            i += 1
    return printer

printer_1 = printer_factory(book_1)

printer_1()
printer_1()

I agree with nilo. Below is a solution based on his response. In this solution, you will go back to the beginning of the list once you loop the whole list.

book1 = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o']

class Printer:
    def __init__(self, book):
        self.index = 0
        self.book = book

    def print(self, n):

        for i in range(0, n):
            print(self.book[self.index % len(self.book)])
            self.index += 1


book = Printer(book1)
book.print(5)
print("")
book.print(5)
print("")
book.print(7)

Output:

a
b
c
d
e

f
g
h
i
j

k
l
m
n
o
a
b


I have not made much edits to your programme.So this can be a little useful for you in understanding.

book1= ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o']
def print_book(book,a,n):
    printed = book
    if printed != []:
    
        new_list=[]#i have created a list
        for i in range(a,n+1):
            new_list.append(book[i])#append is used to add elements to list
        
        for el in new_list:
                print(el)
    
print_book(book1,0,4)#prints a,b,c,d,e
print_book(book1,5,9)#prints f,g,h,i,j
Related