while otro hacer for ejemplos doble dentro con ciclo bucle anidado list iteration tuples python

otro - Iterar sobre pares en una lista(moda circular) en Python



hacer ciclo for en python (13)

Aquí hay una versión que admite un índice de inicio opcional (por ejemplo, para devolver (4, 0) como el primer par, use start = -1:

import itertools def iterrot(lst, start = 0): if start == 0: i = iter(lst) elif start > 0: i1 = itertools.islice(lst, start, None) i2 = itertools.islice(lst, None, start) i = itertools.chain(i1, i2) else: # islice doesn''t support negative slice indices so... lenl = len(lst) i1 = itertools.islice(lst, lenl + start, None) i2 = itertools.islice(lst, None, lenl + start) i = itertools.chain(i1, i2) return i def iterpairs(lst, start = 0): i = iterrot(lst, start) first = prev = i.next() for item in i: yield prev, item prev = item yield prev, first def itertrios(lst, start = 0): i = iterrot(lst, start) first = prevprev = i.next() second = prev = i.next() for item in i: yield prevprev, prev, item prevprev, prev = prev, item yield prevprev, prev, first yield prev, first, second

El problema es fácil, quiero iterar sobre cada elemento de la lista y el siguiente en pares (envolviendo el último con el primero).

He pensado en dos formas no epistónicas de hacerlo:

def pairs(lst): n = len(lst) for i in range(n): yield lst[i],lst[(i+1)%n]

y:

def pairs(lst): return zip(lst,lst[1:]+[lst[:1]])

Rendimiento esperado:

>>> for i in pairs(range(10)): print i (0, 1) (1, 2) (2, 3) (3, 4) (4, 5) (5, 6) (6, 7) (7, 8) (8, 9) (9, 0) >>>

alguna sugerencia sobre una forma más pythonic de hacer esto? tal vez hay una función predefinida de la que no he oído hablar?

también podría ser interesante una versión n-fold más general (con trillizos, cuartetos, etc. en lugar de pares).


Esto infinitamente ciclos, para bien o para mal, pero es algorítmicamente muy claro.

from itertools import tee, cycle def nextn(iterable,n=2): '''''' generator that yields a tuple of the next n items in iterable. This generator cycles infinitely '''''' cycled = cycle(iterable) gens = tee(cycled,n) # advance the iterators, this is O(n^2) for (ii,g) in zip(xrange(n),gens): for jj in xrange(ii): gens[ii].next() while True: yield tuple([x.next() for x in gens]) def test(): data = ((range(10),2), (range(5),3), (list("abcdef"),4),) for (iterable, n) in data: gen = nextn(iterable,n) for j in range(len(iterable)+n): print gen.next() test()

da:

(0, 1) (1, 2) (2, 3) (3, 4) (4, 5) (5, 6) (6, 7) (7, 8) (8, 9) (9, 0) (0, 1) (1, 2) (0, 1, 2) (1, 2, 3) (2, 3, 4) (3, 4, 0) (4, 0, 1) (0, 1, 2) (1, 2, 3) (2, 3, 4) (''a'', ''b'', ''c'', ''d'') (''b'', ''c'', ''d'', ''e'') (''c'', ''d'', ''e'', ''f'') (''d'', ''e'', ''f'', ''a'') (''e'', ''f'', ''a'', ''b'') (''f'', ''a'', ''b'', ''c'') (''a'', ''b'', ''c'', ''d'') (''b'', ''c'', ''d'', ''e'') (''c'', ''d'', ''e'', ''f'') (''d'', ''e'', ''f'', ''a'')


Esto podría ser satisfactorio:

def pairs(lst): for i in range(1, len(lst)): yield lst[i-1], lst[i] yield lst[-1], lst[0] >>> a = list(range(5)) >>> for a1, a2 in pairs(a): ... print a1, a2 ... 0 1 1 2 2 3 3 4 4 0

Si te gusta este tipo de cosas, mira los artículos de python en wordaligned.org . El autor tiene un amor especial por los generadores en python.


Lo haría así (sobre todo porque puedo leer esto):

class Pairs(object): def __init__(self, start): self.i = start def next(self): p, p1 = self.i, self.i + 1 self.i = p1 return p, p1 def __iter__(self): return self if __name__ == "__main__": x = Pairs(0) y = 1 while y < 20: print x.next() y += 1

da:

(0, 1) (1, 2) (2, 3) (3, 4) (4, 5) (5, 6) (6, 7) (7, 8) (8, 9)


Me he codificado las versiones generales de la tupla, me gusta la primera por su simplicidad elegante, cuanto más la miro, más pitónico me parece ... después de todo, lo que es más pitónico que un trazador de líneas con cremallera , extensión de argumento de asterisco, listas de comprensión, lista de división, lista de concatenación y "rango"?

def ntuples(lst, n): return zip(*[lst[i:]+lst[:i] for i in range(n)])

La versión de itertools debería ser lo suficientemente eficiente incluso para listas grandes ...

from itertools import * def ntuples(lst, n): return izip(*[chain(islice(lst,i,None), islice(lst,None,i)) for i in range(n)])

Y una versión para secuencias no indexables:

from itertools import * def ntuples(seq, n): iseq = iter(seq) curr = head = tuple(islice(iseq, n)) for x in chain(iseq, head): yield curr curr = curr[1:] + (x,)

De todos modos, ¡gracias a todos por sus sugerencias! :-)


Para responder a su pregunta sobre la resolución del caso general:

import itertools def pair(series, n): s = list(itertools.tee(series, n)) try: [ s[i].next() for i in range(1, n) for j in range(i)] except StopIteration: pass while True: result = [] try: for j, ss in enumerate(s): result.append(ss.next()) except StopIteration: if j == 0: break else: s[j] = iter(series) for ss in s[j:]: result.append(ss.next()) yield result

El resultado es así:

>>> for a in pair(range(10), 2): ... print a ... [0, 1] [1, 2] [2, 3] [3, 4] [4, 5] [5, 6] [6, 7] [7, 8] [8, 9] [9, 0] >>> for a in pair(range(10), 3): ... print a ... [0, 1, 2] [1, 2, 3] [2, 3, 4] [3, 4, 5] [4, 5, 6] [5, 6, 7] [6, 7, 8] [7, 8, 9] [8, 9, 0] [9, 0, 1]


Por supuesto, siempre puedes usar un deque :

from collections import deque from itertools import * def pairs(lst, n=2): itlst = iter(lst) start = list(islice(itlst, 0, n-1)) deq = deque(start, n) for elt in chain(itlst, start): deq.append(elt) yield list(deq)


Versión aún más corta de la solución de rango zip * de Fortran (con lambda esta vez;):

group = lambda t, n: zip(*[t[i::n] for i in range(n)]) group([1, 2, 3, 3], 2)

da:

[(1, 2), (3, 4)]


Yo, como siempre, como T:

from itertools import tee, izip, chain def pairs(iterable): a, b = tee(iterable) return izip(a, chain(b, [next(b)]))


[(i,(i+1)%len(range(10))) for i in range(10)]

reemplace el rango (10) con la lista que desea.

En general, la "indexación circular" es bastante fácil en Python; Solo usa:

a[i%len(a)]


def pairs(ex_list): for i, v in enumerate(ex_list): if i < len(list) - 1: print v, ex_list[i+1] else: print v, ex_list[0]

Enumerate devuelve una tupla con el número de índice y el valor. ex_list[i+1] el valor y el siguiente elemento de la lista ex_list[i+1] . El if i < len(list) - 1 significa si v no es el último miembro de la lista. Si es así: imprima v y el primer elemento de la lista print v, ex_list[0] .

Editar:

Puedes hacer que devuelva una lista. Solo agregue las tuplas impresas a una lista y devuelvala.

def pairs(ex_list): result = [] for i, v in enumerate(ex_list): if i < len(list) - 1: result.append((v, ex_list[i+1])) else: result.append((v, ex_list[0])) return result


def pairs(lst): i = iter(lst) first = prev = item = i.next() for item in i: yield prev, item prev = item yield item, first

Funciona en cualquier secuencia no vacía, no se requiere indexación.


i=(range(10)) for x in len(i): print i[:2] i=i[1:]+[i[1]]

más pitónico que esto es imposible