Нужна помощь в сортировке списка объектов по ключу - PullRequest
2 голосов
/ 07 июля 2010

Я не могу получить этот код для сортировки списка объектов, используя .sort () или sorted ().Что мне здесь не хватает?

PS В моем методе solution.distance () тоже можно использовать косметические операции, если у кого-то есть какие-либо предложения.

Спасибо!

import random
import math

POPULATION_SIZE = 100

data = [[1, 565.0, 575.0],
        [2, 25.0, 185.0],
        [3, 345.0, 750.0],
        [4, 945.0, 685.0],
        [5, 845.0, 655.0],
        [6, 880.0, 660.0],
        [7, 25.0, 230.0],
        [8, 525.0, 1000.0],
        [9, 580.0, 1175.0],
        [10, 650.0, 1130.0]
        ]

class Solution():

  def __init__(self):
    self.dna = []
    self.randomize()

  def randomize(self):
    temp = data[:]
    while len(temp) > 0:
      self.dna.append( temp.pop( random.randint( 0,len(temp)-1 ) ) ) 

  def distance(self): 
    total = 0 
    #There has to be a better way to access two adjacent elements.
    for i, points in enumerate(self.dna):
      if i < (len(self.dna)-1): 
        total += math.sqrt( (points[1]-self.dna[i+1][1])**2 + (points[2]-self.dna[i+1][2])**2 )
      else:
        total += math.sqrt( (points[1]-self.dna[0][1])**2 + (points[2]-self.dna[0][2])**2 )
    return int(total)


class Population():

  def __init__(self):
    self.solutions = []
    self.generation = 0

    #Populate with solutions
    self.solutions = [Solution() for i in range(POPULATION_SIZE)]


  def __str__(self):

    result = ''

    #This is the part that is not returning sorted results.  I tried sorted() too.
    self.solutions.sort(key=lambda solution: solution.distance, reverse=True)


    for solution in self.solutions:
      result += 'ID: %s - Distance: %s\n' % ( id(solution),  solution.distance() )

    return result


if __name__ == '__main__':

  p = Population()
  print p

Ответы [ 3 ]

3 голосов
/ 07 июля 2010

Изменение

key=lambda solution: solution.distance

до

key=lambda solution: solution.distance()

(скобки необходимы для вызова функции.)

Кроме того, вы можете сделать метод distance свойством:

  @property
  def distance(self): 
      ....

В этом случае измените все вхождения solution.distance() на solution.distance. Я думаю, что это альтернативное решение немного приятнее, поскольку оно удаляет два символа беспорядка (парены) каждый раз, когда вы хотите поговорить о расстоянии.

PS. key=lambda solution: solution.distance возвращал связанный метод solution.distance для каждого solution в self.solutions. Поскольку один и тот же объект возвращался в качестве ключа для каждого solution, желаемое упорядочение не произошло.

1 голос
/ 07 июля 2010

Вот лучший способ написать цикл в distance(): поместите следующее определение функции, взятое из документации itertools , в свой код:

from itertools import izip, tee
def pairwise(iterable):
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

Затем вы можете написать distance, чтобы воспользоваться преимуществами эффективных процедур Python для манипулирования итераторами, например:

from itertools import chain, islice
def distance(self): 
    all_pairs = islice(pairwise(chain(self.dna, self.dna)), 0, len(self.dna))
    return sum(math.sqrt((p[1]-q[1])**2 + (p[2]-q[2])**2) for p,q in all_pairs)

Это должно быть достаточно эффективно, даже если массив dna очень длинный.

1 голос
/ 07 июля 2010

Вот попытка очистить ваш класс, используя методы функционального программирования:

import random

class Solution():

  def __init__(self):
    self.dna = []
    self.randomize()

  def randomize(self):
    self.dna = data
    random.shuffle(self.dna)

  def distance(self):
    # Return the distance between two points.
    def point_distance((p1, p2)):
      return math.sqrt((p1[1]-p2[1])**2) + (p1[2]-p2[2])**2)
    # sums the distances between consecutive points.
    # zip pairs consecutive points together, wrapping around at end.
    return int(sum(map(point_distance, zip(self.dna, self.dna[1:]+self.dna[0:1])))

Это не проверено, но должно быть близко к работе.Кроме того, предлагается использовать класс вместо трехэлементного списка для данных.Это сделает ваш код намного понятнее:

   def point_distance((p1, p2)):
      return math.sqrt((p1.x-p2.x)**2) + (p1.y-p2.y)**2)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...