Related
I need to iterate over a circular list, possibly many times, each time starting with the last visited item.
The use case is a connection pool. A client asks for connection, an iterator checks if pointed-to connection is available and returns it, otherwise loops until it finds one that is available.
How can I do this neatly in Python?
If you instead need an immediately created list of the results up to a certain length, rather than iterating on demand: see Repeat list to max number of elements for general techniques, and How to replicate array to specific length array for Numpy-specific techniques.
Use itertools.cycle, that's its exact purpose:
from itertools import cycle
lst = ['a', 'b', 'c']
pool = cycle(lst)
for item in pool:
print item,
Output:
a b c a b c ...
(Loops forever, obviously)
In order to manually advance the iterator and pull values from it one by one, simply call next(pool):
>>> next(pool)
'a'
>>> next(pool)
'b'
The correct answer is to use itertools.cycle. But, let's assume that library function doesn't exist. How would you implement it?
Use a generator:
def circular():
while True:
for connection in ['a', 'b', 'c']:
yield connection
Then, you can either use a for statement to iterate infinitely, or you can call next() to get the single next value from the generator iterator:
connections = circular()
next(connections) # 'a'
next(connections) # 'b'
next(connections) # 'c'
next(connections) # 'a'
next(connections) # 'b'
next(connections) # 'c'
next(connections) # 'a'
#....
Or you can do like this:
conn = ['a', 'b', 'c', 'd', 'e', 'f']
conn_len = len(conn)
index = 0
while True:
print(conn[index])
index = (index + 1) % conn_len
prints a b c d e f a b c... forever
you can accomplish this with append(pop()) loop:
l = ['a','b','c','d']
while True:
print l[0]
l.append(l.pop(0))
or for i in range() loop:
l = ['a','b','c','d']
ll = len(l)
while True:
for i in range(ll):
print l[i]
or simply:
l = ['a','b','c','d']
while True:
for i in l:
print i
all of which print:
>>>
a
b
c
d
a
b
c
d
...etc.
of the three I'd be prone to the append(pop()) approach as a function
servers = ['a','b','c','d']
def rotate_servers(servers):
servers.append(servers.pop(0))
return servers
while True:
servers = rotate_servers(servers)
print servers[0]
If you wish to cycle n times, implement the ncycles itertools recipe:
from itertools import chain, repeat
def ncycles(iterable, n):
"Returns the sequence elements n times"
return chain.from_iterable(repeat(tuple(iterable), n))
list(ncycles(["a", "b", "c"], 3))
# ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']
You need a custom iterator -- I'll adapt the iterator from this answer.
from itertools import cycle
class ConnectionPool():
def __init__(self, ...):
# whatever is appropriate here to initilize
# your data
self.pool = cycle([blah, blah, etc])
def __iter__(self):
return self
def __next__(self):
for connection in self.pool:
if connection.is_available: # or however you spell it
return connection
In order to avoid infinite loop, I have used length of array to iterate only until size of list is double.You can implement your own pre condition .Idea is to avoid infinite loop.
#Implement Circular Linked List
from itertools import cycle
list=[1,2,3,4,5]
lstlength=len(list)*2
print(lstlength)
pool=cycle(list)
i=0
#To avoid infinite loop break when you have iterated twice size of the list
for items in pool:
print(items)
if i >lstlength:
break
i += 1
class A(object):
def __init__(self, l):
self.strt = 0
self.end = len(l)
self.d = l
def __iter__(self):
return self
def __next__(self):
val = None
if self.strt>=self.end:
self.strt=0
val = self.d[self.strt]
self.strt += 1
return val
a= A([8,9,7,66])
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
For those, who may be interested.
To loop forward or backward starting from given index:
def loop_fwd(arr, index):
while True:
arr_index = index % len(arr)
yield arr_index, arr[arr_index]
index += 1
def loop_bcw(arr, index):
while True:
arr_index = index % len(arr)
yield arr_index, arr[arr_index]
index -= 1
forward_it = loop_fwd([1,2,3,4,5], 3)
backward_it = loop_bcw([1,2,3,4,5], 3)
print('forward:')
for i in range(10):
print(next(forward_it))
print('backward:')
for i in range(10):
print(next(backward_it))
I’m having trouble writing a generator function that takes an iterable and one more parameter which is an integer x. It outputs every value except for the last x values. It doesn’t know how to count how many values the iterable outputs.
I don’t know how to do this using a while loop as well as iter. I also need to use a comprehension that creates a list to store x values at most.
Lets say we call :
for i in func_function(“abcdefghijk”,5):
print(i,end =”)
It should print abcdef.
Here's what I've tried:
def func_function(iterable, x):
while True:
l = []
for x in iter(iterable):
if len(x) == x:
yield x
The trick is to turn this from lookahead into lookbehind.
I'd do this by iterating over the input and maintaining a window of the most recent n elements:
def except_last_n(iterable, n):
last_n = []
for val in iterable:
last_n.append(val)
if len(last_n) > n:
yield last_n.pop(0)
for val in except_last_n(range(10), 3):
print(val)
Rewriting this as a while loop and iter is left as exercise for the reader.
def except_last_n(iterable, n):
last_n = [val for val in iterable]
if len(last_n) > n:
yield last_n.pop(0)
from collections import deque
def drop_last_few(iterable, x=5):
it = iter(iterable)
data = deque(maxlen=x)
data.extend([next(it) for i in range(x)])
for val in it:
yield data[0]
data.append(val)
This uses a double-ended queue as storage to cache at most x elements. Demo:
>>> print(*drop_last_few("abcdefghijk", 5))
a b c d e f
Strings are sliceable:
def func_function(iterable, x):
yield from iterable[:-x]
print(func_function("asdfgkjbewqrfgkjb",8))
k = list(func_function("asdfgkjbewqrfgkjb",8))
print(k) # ['a', 's', 'd', 'f', 'g', 'k', 'j', 'b', 'e']
The while loop, iter and l=[] are not needed...
I need to iterate over a circular list, possibly many times, each time starting with the last visited item.
The use case is a connection pool. A client asks for connection, an iterator checks if pointed-to connection is available and returns it, otherwise loops until it finds one that is available.
How can I do this neatly in Python?
If you instead need an immediately created list of the results up to a certain length, rather than iterating on demand: see Repeat list to max number of elements for general techniques, and How to replicate array to specific length array for Numpy-specific techniques.
Use itertools.cycle, that's its exact purpose:
from itertools import cycle
lst = ['a', 'b', 'c']
pool = cycle(lst)
for item in pool:
print item,
Output:
a b c a b c ...
(Loops forever, obviously)
In order to manually advance the iterator and pull values from it one by one, simply call next(pool):
>>> next(pool)
'a'
>>> next(pool)
'b'
The correct answer is to use itertools.cycle. But, let's assume that library function doesn't exist. How would you implement it?
Use a generator:
def circular():
while True:
for connection in ['a', 'b', 'c']:
yield connection
Then, you can either use a for statement to iterate infinitely, or you can call next() to get the single next value from the generator iterator:
connections = circular()
next(connections) # 'a'
next(connections) # 'b'
next(connections) # 'c'
next(connections) # 'a'
next(connections) # 'b'
next(connections) # 'c'
next(connections) # 'a'
#....
Or you can do like this:
conn = ['a', 'b', 'c', 'd', 'e', 'f']
conn_len = len(conn)
index = 0
while True:
print(conn[index])
index = (index + 1) % conn_len
prints a b c d e f a b c... forever
you can accomplish this with append(pop()) loop:
l = ['a','b','c','d']
while True:
print l[0]
l.append(l.pop(0))
or for i in range() loop:
l = ['a','b','c','d']
ll = len(l)
while True:
for i in range(ll):
print l[i]
or simply:
l = ['a','b','c','d']
while True:
for i in l:
print i
all of which print:
>>>
a
b
c
d
a
b
c
d
...etc.
of the three I'd be prone to the append(pop()) approach as a function
servers = ['a','b','c','d']
def rotate_servers(servers):
servers.append(servers.pop(0))
return servers
while True:
servers = rotate_servers(servers)
print servers[0]
If you wish to cycle n times, implement the ncycles itertools recipe:
from itertools import chain, repeat
def ncycles(iterable, n):
"Returns the sequence elements n times"
return chain.from_iterable(repeat(tuple(iterable), n))
list(ncycles(["a", "b", "c"], 3))
# ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']
You need a custom iterator -- I'll adapt the iterator from this answer.
from itertools import cycle
class ConnectionPool():
def __init__(self, ...):
# whatever is appropriate here to initilize
# your data
self.pool = cycle([blah, blah, etc])
def __iter__(self):
return self
def __next__(self):
for connection in self.pool:
if connection.is_available: # or however you spell it
return connection
In order to avoid infinite loop, I have used length of array to iterate only until size of list is double.You can implement your own pre condition .Idea is to avoid infinite loop.
#Implement Circular Linked List
from itertools import cycle
list=[1,2,3,4,5]
lstlength=len(list)*2
print(lstlength)
pool=cycle(list)
i=0
#To avoid infinite loop break when you have iterated twice size of the list
for items in pool:
print(items)
if i >lstlength:
break
i += 1
class A(object):
def __init__(self, l):
self.strt = 0
self.end = len(l)
self.d = l
def __iter__(self):
return self
def __next__(self):
val = None
if self.strt>=self.end:
self.strt=0
val = self.d[self.strt]
self.strt += 1
return val
a= A([8,9,7,66])
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
For those, who may be interested.
To loop forward or backward starting from given index:
def loop_fwd(arr, index):
while True:
arr_index = index % len(arr)
yield arr_index, arr[arr_index]
index += 1
def loop_bcw(arr, index):
while True:
arr_index = index % len(arr)
yield arr_index, arr[arr_index]
index -= 1
forward_it = loop_fwd([1,2,3,4,5], 3)
backward_it = loop_bcw([1,2,3,4,5], 3)
print('forward:')
for i in range(10):
print(next(forward_it))
print('backward:')
for i in range(10):
print(next(backward_it))
I've got a script running that I want to toggle between different variables.
Let's say I've got a list of urls and I want to concatenate one of the variables a, b or c. I don't care which but I'd expect the variables to repeat but the list would run through once.
v would end up looking like
url1+string1
url2+string2
url3+string3
url4+string1
url5+string2
etc
def function1():
list = [url1,url2,url3,url4,url5.......]
a = 'string1'
b = 'string2'
c = 'string3'
for i in list:
v = i+(a then b then c then a then b then c)
I was able to get this to work on my own but I'm new and learning, does anyone have a more elegant solution to this?
a = 'a'
b = 'b'
c = 'c'
list1 = ['string1','string2','string3','string4','string5','string6','string7','string8']
list2 = [a, b, c]
c = 0
for i in list1:
if c == len(list2):
c = 0
vv = i + list2[int(c)]
c = c + 1
print vv
it returns what I was looking for but it's messy:
string1a
string2b
string3c
string4a
string5b
string6c
string7a
string8b
You can utilise itertools.cycle to repeat one of the iterables, eg:
from itertools import cycle, izip
list1 = ['string1','string2','string3','string4','string5','string6','string7','string8']
list2 = ['a', 'b', 'c']
for fst, snd in izip(list1, cycle(list2)):
print fst + snd # or whatever
#string1a
#string2b
#string3c
#string4a
#string5b
#string6c
#string7a
#string8b
Note that while cycle will repeat its elements indefinitely, izip stops on the shortest iterable (list1).
list = [url1..1]
list2 = [a, b, c]
for i in list:
for a in list2:
v = i+a
EDIT
Okay, that makes more sense-
How about this...
set_it = iter(list2)
for i in list:
try:
a = set_it.next()
except:
set_it = iter(list2)
a = set_it.next()
v = i+a
Though I feel the same as you- there is probably a smoother way to accomplish that...
Hi I am new to programming and want to learn python. I am working on a code that should return items that are most redundant in a list. If there are more than 1 then it should return all.
Ex.
List = ['a','b','c','b','d','a'] #then it should return both a and b.
List = ['a','a','b','b','c','c','d'] #then it should return a b and c.
List = ['a','a','a','b','b','b','c','c','d','d','d'] #then it should return a b and d.
Note: We don't know what element is most common in the list so we have to find the most common element and if there are more than one it should return all. If the list has numbers or other strings as elements then also the code has to work
I have no idea how to proceed. I can use a little help.
Here is the whole program:
from collections import Counter
def redundant(List):
c = Counter(List)
maximum = c.most_common()[0][1]
return [k for k, v in c.items()if v == maximum]
def find_kmers(DNA_STRING, k):
length = len(DNA_STRING)
a = 0
List_1 = []
string_1 = ""
while a <= length - k:
string_1 = DNA_STRING[a:a+k]
List_1.append(string_1)
a = a + 1
redundant(List_1)
This program should take DNA string and length of kmer and find what are the kemers of that length that are present in that DNA string.
Sample Input:
ACGTTGCATGTCGCATGATGCATGAGAGCT
4
Sample Output:
CATG GCAT
You can use collections.Counter:
from collections import Counter
def solve(lis):
c = Counter(lis)
mx = c.most_common()[0][1]
#or mx = max(c.values())
return [k for k, v in c.items() if v == mx]
print (solve(['a','b','c','b','d','a']))
print (solve(['a','a','b','b','c','c','d']))
print (solve(['a','a','a','b','b','b','c','c','d','d','d'] ))
Output:
['a', 'b']
['a', 'c', 'b']
['a', 'b', 'd']
A slightly different version of the above code using itertools.takewhile:
from collections import Counter
from itertools import takewhile
def solve(lis):
c = Counter(lis)
mx = max(c.values())
return [k for k, v in takewhile(lambda x: x[1]==mx, c.most_common())]
inputData = [['a','b','c','b','d','a'], ['a','a','b','b','c','c','d'], ['a','a','a','b','b','b','c','c','d','d','d'] ]
from collections import Counter
for myList in inputData:
temp, result = -1, []
for char, count in Counter(myList).most_common():
if temp == -1: temp = count
if temp == count: result.append(char)
else: break
print result
Output
['a', 'b']
['a', 'c', 'b']
['a', 'b', 'd']
>>> def maxs(L):
... counts = collections.Counter(L)
... maxCount = max(counts.values())
... return [k for k,v in counts.items() if v==maxCount]
...
>>> maxs(L)
['a', 'b']
>>> L = ['a','a','b','b','c','c','d']
>>> maxs(L)
['a', 'b', 'c']
>>> L = ['a','a','a','b','b','b','c','c','d','d','d']
>>> maxs(L)
['d', 'a', 'b']
Just for the sake of giving a solution not using collections & using list comprehensions.
given_list = ['a','b','c','b','d','a']
redundant = [(each, given_list.count(each)) for each in set(given_list) if given_list.count(each) > 1]
count_max = max(redundant, key=lambda x: x[1])[1]
final_list = [char for char, count in redundant if count == count_max]
PS - I myself haven't used Counters yet :( Time to learn!