Hello, there is the following task:

There are 2 txt files (the number of lines in each is arbitrary). It is necessary to insert lines from one list into another at a certain interval, for example, after every n lines.

f1 = open(r'c:\Исходная база.txt') f2 = open(r'c:\Строки для добавления.txt') list1 = f1.readlines() list2 = f2.readlines() f1.close() f2.close() i = 0 n = 2 while i + n <= 10: list1.insert(i * n, list2[i]) i = i + 1 with open(r'c:\результат.txt', 'w') as res: for item in list1: res.write("{}".format(item)) 

In case you specify

 while i + n <= len(list2): 

list2 - file from where we take the string for substitution, the code works as it should.

However, with

 while i + n <= len(list1): 

I get the error:

 list1.insert(i * n, list2[i]) IndexError: list index out of range 

I ask you to suggest how to implement the substitution of rows from list2 in the case if there are fewer rows in list2 than in list1. That is, when the lines in list2 run out, string substitution should start again from 0 on list2 again.

 Исходные данные list1: 1, 2, 3, 4, .., m Исходные данные List2: a, b, c, d, .., k Результат должен быть: 1, a, 2, b, 3, c ... при n=2 1, 2, a, 3, 4, b, .. при n=3 

At the same time it is important that the lines are substituted from list2 to list1. And when the lines in list2 run out, they should begin to be substituted again with 0 elements.

  • one
    Better instead of a sheet of text, show the source data and what should happen :) - gil9red
  • one
    Data List1: 1 2 3 4 .. m data list2: abcd .. k Total: 1 a 2 b 3 c if n = 2 or 1 2 a 3 4 b, if n = 3 - Kir
  • one
    So much better :) - gil9red

2 answers 2

To return items in a circle (start from the first to the end), itertools.cycle() can be used.

To bypass several elements at once, you can use the zip(*[iterator]*n) idiom.

To alternate groups from the first iterator with elements from the second and return the flat version (without recursion) and trimming the input along the shorter argument length:

 import itertools flatten = itertools.chain.from_iterable def interlaced(groups, items): return flatten(itertools.chain(group, [item]) for group, item in zip(groups, items)) 

Combining:

 n = 3 lines = interlaced(zip(*[itertools.cycle(f1)]*(n-1)), f2) output_file.writelines(lines) 

Example:

 f1 = iter([1,2,3,4]) f2 = iter("abcde") it = interlaced(zip(*[itertools.cycle(f1)]*(n-1)), f2) print(*it) # -> 1 2 a 3 4 b 1 2 c 3 4 d 1 2 e 

    Use the itertools module:

     In [1]: l1 = [1,2,3,4] In [2]: l2 = list('abcde') In [3]: from itertools import zip_longest, chain, cycle In [4]: list(chain.from_iterable(zip(cycle(l1), l2))) Out[4]: [1, 'a', 2, 'b', 3, 'c', 4, 'd', 1, 'e'] 
    • Is it possible to make so that instead of "None" it is again substituted with "1"? The problem is exactly this. - Kir
    • @Kir you can use itertools.cycle : list(chain.from_iterable(zip(cycle(l1), l2))) - Sergey Gornostaev
    • @SergeyGornostaev, yes, thanks, I was just about to add an example ... - MaxU
    • @MaxU yes not for that :) - Sergey Gornostaev
    • @Kir, added an appropriate example - MaxU