how to iterate/zip elements of multiple list with random index as start position

Question:

I have multiple lists of equal length as follows:

list1 = ["a", "b", "c", "d", "e", "f"]
list2 = ["g", "h", "i", "j", "k", "l"]
list3 = ["m", "n", "o", "p", "q", "r"]
list4 = ["s", "t", "u", "v", "w", "x"]

listpack = [list1, list2, list3, list4]

#random select one element per list
rand = more_itertools.random_product(*listpack)


#locate their index
for ii in rand:                  #strings
    for xx in listpack:             #list of lists
        pass
    index = xx.index(ii[:])
    

Problem area:
How to cycle round all the list using the above index as start position

for example:
if the rand result above is ("d, h, q, v")
next will be ("e, i, r, w"), ("f, j, m, x"), ("a, k, n, s")
till the cycle reach their starting position again)

I have tried to zip but it always start from the beginning of the list

cyclist = list(map(''.join, zip(*listpack))) 

I have also checked all thread suggested by stacks but not related to this.
Any faster approach to the entire code is also welcome 🙂

Thanks

Asked By: 7r0jan005

||

Answers:

From lists

You can use this:

import more_itertools as mi

list1 = ["a", "b", "c", "d", "e", "f"]
list2 = ["g", "h", "i", "j", "k", "l"]
list3 = ["m", "n", "o", "p", "q", "r"]
list4 = ["s", "t", "u", "v", "w", "x"]

listpack = [list1, list2, list3, list4]

rand = mi.random_product(*listpack)
indexes = [l.index(r) for l, r in zip(listpack, rand)]

for i in range(len(list1)):
    for j in range(len(listpack)):
        k = (indexes[j] + i) % len(listpack[j])
        print(listpack[j][k], end='')
    print('')

Output:

Run 1

birt
cjmu
dknv
elow
fgpx
ahqs

Run 2

cjov
dkpw
elqx
fgrs
ahmt
binu

From files

For files, use:

import more_itertools as mi

filenames = ['list1.txt', 'list2.txt', 'list3.txt', 'list4.txt']

listpack = []

for filename in filenames:
    with open(filename) as f:
        listpack.append(f.read().splitlines())

rand = mi.random_product(*listpack)
indexes = [l.index(r) for l, r in zip(listpack, rand)]

for i in range(len(listpack[0])):
    for j in range(len(listpack)):
        k = (indexes[j] + i) % len(listpack[j])
        print(listpack[j][k], end='')
    print('')

list1.txt:

a
b
c
d
e
f

Output:

djru
ekmv
flnw
agox
bhps
ciqt

Only one print / output stored in variable

If you want only one print the use the following instead of the loop:

output = []

for i in range(len(listpack[0])):
    output.append('')
    for j in range(len(listpack)):
        k = (indexes[j] + i) % len(listpack[j])
        output[-1] += listpack[j][k]

print(output)

Output:

['dgrv', 'ehmw', 'finx', 'ajos', 'bkpt', 'clqu']
Answered By: The Thonnu

One approach using the standard library:

import random

# for reproducibility
random.seed(43)

list1 = ["a", "b", "c", "d", "e", "f"]
list2 = ["g", "h", "i", "j", "k", "l"]
list3 = ["m", "n", "o", "p", "q", "r"]
list4 = ["s", "t", "u", "v", "w", "x"]

# generate random starting points for each list
s1 = random.randrange(0, len(list1))
s2 = random.randrange(0, len(list2))
s3 = random.randrange(0, len(list3))
s4 = random.randrange(0, len(list4))

for tup in zip(list1[s1:] + list1[:s1], list2[s1:] + list2[:s1], list3[s1:] + list3[:s1], list4[s1:] + list4[:s1]):
    print(tup)

Output

('a', 'g', 'm', 's')
('b', 'h', 'n', 't')
('c', 'i', 'o', 'u')
('d', 'j', 'p', 'v')
('e', 'k', 'q', 'w')
('f', 'l', 'r', 'x')

The function random.randrange will generate a random index. Then you could use the expression:

list1[s1:] + list1[:s1]

To generate a cycle of the original list, for example for list1 and s1 = 2, the above expression returns:

['c', 'd', 'e', 'f', 'a', 'b']
Answered By: Dani Mesejo
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.