Несколько вопросов о выражениях-генераторах и быстрых альтернативах - PullRequest
2 голосов
/ 28 ноября 2010

Рассмотрим следующий код, который является неотъемлемой частью моих вопросов ниже:

import functools

N = 3

class Struct:
    """Create an instance with argument=value slots.
    This is for making a lightweight object whose class doesn't matter."""
    def __init__(self, **entries):
        self.__dict__.update(entries)

    def __repr__(self):

        args = ['%s=%s' % (k, repr(v)) for (k, v) in vars(self).items()]
        return '\nStruct(%s)' % ', '.join(args)

def doit( move ):

    ( rowIn, colIn ) = move
    something = rowIn  + ( 10 * colIn ) # An involved computation here in real life

    return Struct( coord = ( rowIn, colIn ), something = something )

legalStates = [ ( row, col ) for row in xrange( N ) for col in xrange( N ) ] # A more complicated function that generates the list in real life. Call it 'complicatedFunction'

genExpFn = lambda : ( ( s.something, m, s ) for ( m, s ) in ( ( move, doit( move ) ) for move in legalStates ) )  #Q1

successorsSortedGenFn = lambda : ( p for p in sorted( genExpFn(), reverse = True ) )

def bFunc( s, a ):

    #print "a * s ->", a * s
    return a * s # An involved computation here in real life

def aFunc( ( v, m, s ) ): #Q2

    assert( s.something == v )
    return bFunc( s.something, 10 )

print "min( successorsSortedGen ) -> " + str( min( successorsSortedGenFn(), key=functools.partial( aFunc )) ) #Q3
print
print "max( successorsSortedGen ) -> " + str( max( successorsSortedGenFn(), key=functools.partial( aFunc )) ) #Q4

Мои вопросы основаны на утверждениях, помеченных как "#Q":

Q1 : Очевидно, что генератор полностью создан (все элементы выполнены), так как мы вызываем для него sorted() (который генерирует все элементы и создает временный несортированный список, который он сортирует и возвращает как новый список?).

Есть ли эффективный для пространства способ, который минимизирует создание временных файлов и дает отсортированный список?

Я пытался, но не смог написать понимание списка, которое могло бы сортировать вplace with list.sort()

Это было то выражение, о котором я думал:

successorsSorted = [ ( s.something, m, s ) for ( m, s ) in ( ( move, doit( move ) ) for move in legalStates ) ].sort( reverse = True )

Q2 : обратите внимание, что aFunc - это просто оболочка вокругbFunc 'потому что я не смог написать эквивалентное представление в вызове functools.partial( aFunc ).

Какое выражение' aFunc 'в functools.partial( aFunc ), которое я ищу, , которое позволит мне вызвать'bFunc' напрямую ?


РЕДАКТИРОВАТЬ : Ответ на вопрос 2: lambda ( v, m, s ): bFunc(s.something, 10)

Таким образом, утверждения становятся:

print "min( successorsSortedGen ) -> " + str( min( successorsSortedGenFn(), key=functools.partial( lambda ( v, m, s ): bFunc(s.something, 10)) ) )
print
print "max( successorsSortedGen ) -> " + str( max( successorsSortedGenFn(), key=functools.partial( lambda ( v, m, s ): bFunc(s.something, 10)) ) )

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


Q3, Q4 : Обратите внимание, что элементы перешли в min () и max () уже отсортированы.

Могу ли я сделать эту подсказку для min () и max (), чтобы он не создавал весь список как временный, а затем перебирал весьсписок для поиска элемента min или max?

Если нет, существует ли модуль или пользовательская функция, которая не создает экземпляр всего списка, но, учитывая, что список, переданный ему, отсортирован, возвращает minили максимальный элемент при проверке наименьшего количества элементов ?

1 Ответ

2 голосов
/ 28 ноября 2010

Q1.[x for x in somelist].sort() создает список и вызывает метод sort.Возвращает None Назначение присваивает None successorSorted.Если вы хотите сделать это, вам придется реализовать это самостоятельно, и, вероятно, это будет намного медленнее, чем встроенная сортировка, создающая временный список.

Q2.Вы можете разобрать объект кода и переставить список аргументов так, чтобы a был первым аргументом, а затем переписать весь байт-код, чтобы учесть новые позиции местных жителей.(Да, это действительно может быть сделано).Затем вы можете использовать functools.partial для этого.Или вы можете использовать оболочку, как вы делаете сейчас или несколькими другими способами.Я +1 на обертке.(хотя дайте мне знать, если вы хотите взломать байт-код, я думаю, что они забавны, и клевая вещь о предоставлении их в качестве ответов на переполнение стека состоит в том, что я могу написать их, но не должен их использовать;)

Q3, Q4.На самом деле, нет.Чтобы получить десятый элемент итератора, вам нужно пройти все предыдущие.Если вы знаете, что вам нужен первый элемент, вы можете просто сделать

smallest = next(sorted_iterator)

и для последнего

for item in iterable: pass
largest = item

Первый будет есть первый элемент итератора, а последний будетсъешь весь свой итератор.Пока, итератор.

...