[Python-es] Iterar 2 veces sobre 1 lista y comparar sus objetos lo mas rapido

lopz lowlifebob en gmail.com
Lun Mayo 9 00:17:06 CEST 2011


Hola, estoy haciendo unas pequeñas pruebas en pygame

tengo un diccionario de palabras con tus tags, cada palabra será una
bola y si alguna de las palabras tiene igual tag que otra
entonces se unirán con una línea, y así hasta iterar sobre toda el diccionario
actualmente tengo esto y funciona bien

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pygame
import random

class Neurons():#pygame.sprite.Sprite):
    def __init__(self, x, y, color, key, tags):
        self.x = x
        self.y = y
        self.color = color

        self.key = key
        self.tags = tags

    def draw(self, surf):
        pygame.draw.circle(surf, self.color, [self.x, self.y], 10)

    def pos(self):
        return (self.x, self.y)

def line(surf, start, end):
    pygame.draw.line(surf, read, start, end, 1)

words = {'uno': '1 2 3',
        'dos': '3 4 5',
        'tres': '5 6 7',
        'cuatro': '2 5 8',
        'cinco': '5 3 7',
        'seis': '7 6 3'}

pygame.init()

black = [0, 0, 0]
white = [255, 255, 255]
read = [255, 0, 0]

# Set the height and width of the screen
size = [400, 400]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Net")

neurons = []

for word in words:
    x = random.randrange(100, 400)
    y = random.randrange(100, 400)
    neuron = Neurons(x, y, white, word, words[word])
    neurons.append(neuron)

clock = pygame.time.Clock()

def compare(tags1, tags2):
    for i in tags1.split(' '):
        for j in tags2.split(' '):
            if (i == j):
                return  True
    return False

neurons2 = neurons[:]

done = False
while not done:
    for event in pygame.event.get(): # User did something
        if event.type == pygame.QUIT:
            done = True

    screen.fill(black)

    for i in range(len(neurons)):
        neurons[i].draw(screen)
        #neuron =  neurons.pop()
        #neuron = neurons[i]
        #neurons.remove(neurons[i])
        for j in range(len(neurons)):
            if (i != j):
                if compare(neurons[i].tags, neurons[j].tags):
                    #print neurons[i].tags, neurons[j].tags
                    #print neuron.tags
                    line(screen, neurons[i].pos(), neurons[j].pos())



    pygame.display.flip()
    clock.tick(20)

pygame.quit()



Resulta que siempre hacía dos 2 anidados e iba comparando uno con
todos, pero ahora que me doy cuenta estoy gastando recursos
por que si una palabra y sus tags, por ej
bar: 1, 2, 3
y otra palabra
foo: 4, 2, 5
Resulta que tienen el tag 2 en común, y cuando se itera primero bar y
luego foo entonces se traza una línea entre palabras, pero cuando la
iteración
le toque a foo en el primer for y en el segundo a bar, tendrán la
mismo tag en común, entonces:
Se trazarían 2 líneas, una desde bar -> foo y otra de foo -> bar pero
como tienen los mismos puntos parece ser que es una sola línea.

Entonces he decidio cojer un objeto y eliminarlo de la lista, con pop
e iterar de nuevo pero en el segundo for ya no habría ese objeto
entonces
me ahorraría ese if ( i != j) y además menos una iteración, la próxima
menos 2 y así hasta la mitad, de funcionar funciona
el problema está en que como todo tiene que repetirse con el while la
lista está vacía para el 2do while jeje hay alguna forma de quitar de
la lista un objeto pero sin eliminarlo?
de seguro que es fácil pero no me doy cuenta :(
He intentado con copiar a otra lista, pero en la 2da iteración del
while ya está vacía, además no es la idea copir otra lista si no
remover en el primer for el objeto
para que en el 2do ya no se itere y no tenga que comparar si es el
mismo y además será mucho más rápido

gracias :)

-- 
lopz es libre, usa --> GNU/linux gentoo

+--[RSA 2048]--+
|  ..o.o=+       |
|   o =o*.+      |
|  . . *oO .      |
|     .EBoo      |
|      o.S         |
+--[lopz.org]--+


Más información sobre la lista de distribución Python-es