Как я эффективно фильтрую вычисленные значения в понимании списка Python?

Что касается комментария, который я оставил вам.

У вас есть как минимум три состояния, когда вы извлекаете данные в пользовательский интерфейс. В этом случае я бы порекомендовал вам использовать агрегацию для извлечения данных в качестве модели вашего бизнеса.

Например, проблема, с которой вы столкнулись, заключается в том, что иногда вы не знаете о максимальном или минимальном значении для age или yearsActive , но также должны иметь идентификатор, который может быть ObjectId , который будет использоваться для обновления модели, идентифицируемой этим свойством.

Artist.aggregate([
{
    $match: { age: { $gte: 19, $lte: 44 } }
},
{
    $sort: { yourProperty: 1 }
},
{
    $skip: 10
},
{
    $limit: 10
},
{
    $project: {
        // You set your properties to retrieve with the 1 as flag
        propertieX: 1,
        "another.property": 1,
        "age.max": {
            $cond: {
                if: { $eq: [ "", "$age.max" ] },
                then: 0, // Or the value that you want to set it
                else: "$age.max"
            }
        }
    }
}]);

Другое состояние - когда вы делаете запрос в соответствии с параметрами, которые вы отправляете из формы.

Если вы уверены, что получите модель с логикой, как вы хотите. Например, вы должны возвращать эту модель в каждом запросе, используя $ project и применяя значения по умолчанию, когда их не существует, манипулирование на стороне интерфейса, как при поиске, должно быть простым в управлении.

{
    ObjectId: YOUR_OBJECT_ID,
    age: {
        min: YOUR_MIN_VALUE,
        max: YOUR_MAX_VALUE
    },
    yearsActive: {
        min: YOUR_MIN_VALUE,
        max: YOUR_MAX_VALUE
    }
}

Наконец, когда вы отправляете данные, чтобы сохранить их, вы должны отправить всю возвращенную модель, но самое важное - идентифицировать только этот элемент с помощью ObjectId , чтобы выполнить обновление.

ПРИМЕЧАНИЕ. : . Этот подход я буду использовать в соответствии с информацией, которую я понимаю из вашего вопроса. Если мне плохо со мной в интерпретации, дайте мне знать, и если вы хотите поделиться дополнительной информацией или открыть репозиторий для понимания в коде, если мне будет легче понять проблему .

21
задан Nick 24 September 2008 в 22:08
поделиться

9 ответов

Если вычисления уже приятно связываются в функции, как насчет того, чтобы использовать filter и map?

result = filter (None, map (expensive, mylist))

можно использовать itertools.imap, если список является очень большим.

21
ответ дан 29 November 2019 в 06:28
поделиться

Самое очевидное (и я спорил бы самый читаемый), ответ не должен использовать понимание списка или выражение генератора, а скорее реальный генератор:

def gen_expensive(mylist):
    for item in mylist:
        result = expensive(item)
        if result:
            yield result

Это занимает больше горизонтального места, но намного легче видеть то, что это делает сразу, и Вы заканчиваете тем, что не повторили себя.

7
ответ дан 29 November 2019 в 06:28
поделиться
result = [x for x in map(expensive,mylist) if x]

карта () возвратится, список значений каждого объекта в mylist передал дорогому (). Тогда можно перечислить - постигают это и отбрасывают ненужные значения.

Это несколько похоже на вложенное понимание, но должно быть быстрее (так как интерпретатор Python может оптимизировать его довольно легко).

6
ответ дан 29 November 2019 в 06:28
поделиться

Это точно, что генераторы подходят обрабатывать:

result = (expensive(x) for x in mylist)
result = (do_something(x) for x in result if some_condition(x))
...
result = [x for x in result if x]  # finally, a list
  1. Это делает это полностью ясным, что происходит во время каждого этапа конвейера.
  2. Явный по неявному
  3. генераторы Использования везде до заключительного шага, таким образом, никакое большое промежуточное звено не перечисляет

cf: 'Приемы генератора для Системных программистов' David Beazley

5
ответ дан 29 November 2019 в 06:28
поделиться

Придумал мой собственный ответ после минуты мысли. Это может быть сделано с вложенными пониманиями:

result = [y for y in (expensive(x) for x in mylist) if y]

я предполагаю, что работы, хотя я нахожу вложенные понимания, только незначительно читаемы

23
ответ дан 29 November 2019 в 06:28
поделиться

Вы всегда могли memoize эти expensive() функция так, чтобы вызов его во второй раз вокруг был просто поиском для вычисленного значения x.

Вот только одна из многих реализаций memoize как декоратор .

2
ответ дан 29 November 2019 в 06:28
поделиться

Вы могли memoize дорогой (x) (и если Вы называете дорогими (x) часто, Вы, вероятно, должны memoize это любой путь. Эта страница дает реализацию memoize для Python:

http://code.activestate.com/recipes/52201/

Это обладает дополнительным преимуществом, которое дорогой (x) может быть выполнено меньше , чем времена N, так как любые дублирующиеся записи используют записку от предыдущего выполнения.

Примечание, которое это принимает дорогой (x), является истинной функцией и не зависит от внешнего состояния, которое может измениться. Если дорогой (x) действительно зависит от внешнего состояния, и можно обнаружить, когда это изменения состояния, или Вы знаете это привычка изменение во время Вашего понимания списка, то можно сбросить записки перед пониманием.

2
ответ дан 29 November 2019 в 06:28
поделиться

I will have a preference for:

itertools.ifilter(bool, (expensive(x) for x in mylist))

This has the advantage to:

1
ответ дан 29 November 2019 в 06:28
поделиться

Существует простое старое использование цикла for для добавления в список:

result = []
for x in mylist:
    expense = expensive(x)
    if expense:
        result.append(expense)
0
ответ дан 29 November 2019 в 06:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: