I need to do the following in python. I have a list of strings, list, a string to search for, text, and variable containing the number of elements to print, x. I want to iterate through x no. of consecutive elements of the list, wrapping around to the front of list if necessary.
First I need to find the first element in list that has text as a substring. I will then start with the first element of list after that matched element, and continue to iterate through a total of x consecutive elements of the list, wrapping around if necessary.
How would I do this?
x = 11
text = "string5"
list = ["string1", "string2", "string3", "string4", "string5", "string6", "string7"]
# not sure what to do here...
for elem in list:
if text in elem:
#iterate through list, begin with elem and get the next 11 elements
#once you've reached string7, start over with string1`
In this example I want to end up looking at the following 11 elements:
string6
string7
string1
string2
string3
string4
string5
string6
string7
string1
string2
You can use cycle from itertools, maybe in combination with islice and enumerate.
from itertools import cycle, islice
x = 11
text = "string5"
lst = ["string1", "string2", "string3", "string4", "string5", "string6", "string7"]
for i, elem in enumerate(lst):
if text in elem:
next11 = list(islice(cycle(lst), i+1, i+1+x))
print(next11)
print(len(next11))
Output:
['string6', 'string7', 'string1', 'string2', 'string3', 'string4', 'string5', 'string6', 'string7', 'string1', 'string2']
11
For our problem data:
x = 11 #no. of elements to get
text = 'string5' #text to search in elements of list
lst = ['string1', 'string2', 'string3', 'string4', 'string5', 'string6', 'string7']
n = len(lst)
# index of required text
i = lst.index(text)
Algorithm 1: (Cycle & Slice)
Most pythonic way is using the functions, islice and cycle from the itertools module offcourse:
cycle function)slice function)Code:
from itertools import cycle, islice
desired = list( islice( cycle( lst), i+1, i+1+x))
Algorithm 2: (Loop & Modulo Indexing)
A more traditional way would be:
x no. of times starting after the matched index, i+1
modulo indexing Code:
desired = [ lst[ j%n] for j in range(i+1, i+1+x)]
Algorithm 3 - Bad Implementations: (Rotate & Repeat)
Many poor/ slow implementations are also possible e.g. using numpy functions, like roll, tile:
numpy array so as to start it with the element at the matching index, i
x no. of elementsx no. of elementsCode:
def nextx(lst,i,n,x):
ll = np.array(lst)
rll = np.roll(ll, n-i)
trll = np.tile(rll, x%n+1)
return list(trll[:x])
Output:
>>> nextx(lst,5,7,11)
['string6', 'string7', 'string1', 'string2', 'string3', 'string4', 'string5', 'string6', 'string7', 'string1', 'string2']
>>> nextx(lst,5,7,11) == [lst[j%len(lst)] for j in range(5,5+11)] == list(islice(cycle(lst),5,5+11))
True
Timing:
iPython line magic function %timeit shows that Algorithm 1 is not surprisingly ~1.5 and ~11 times faster than 2 and 3 respectively:
>>> %timeit list( islice( cycle( lst), 5, 5+11))
100000 loops, best of 3: 1.83 µs per loop
>>> %timeit [ lst[ j%len(lst)] for j in range(5, 5+11)]
100000 loops, best of 3: 2.76 µs per loop
>>> %timeit nextx(lst,5,7,11)
10000 loops, best of 3: 20.6 µs per loop
Conclusion:
Using itertools is the Fastest and Slickest way to go whenever you can use cycle, islice, count, repeat, etc!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With