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