лямбда по сравнению с производительностью понимания списка

Как упомянуто, большинство свойств должно иметь и метод считывания и метод set; основным исключением к этому являются списки - например:

private readonly List<Foo> bar = new List<Foo>();
public List<Foo> Bar {get { return bar; } } // works fine

, который будет хорошо работать; однако, если XmlSerializer находит метод set - он требует, чтобы это было общедоступно; следующее будет не работа:

public List<Foo> Bar {get; private set;} // FAIL

Другие причины это не могло бы сериализировать:

  • это не общедоступно с, получают и устанавливают (или readonly для поля)
  • , это имеет [DefaultValue] атрибут и с тем значением
  • , это имеет общественность bool ShouldSerializeFoo() метод, который возвратил false
  • , это имеет общественность bool FooSpecified {get;set;} свойство или поле, которое возвратило false
  • , это отмечено [XmlIgnore]
  • , это отмечено [Obsolete]

, Любой из них заставит это не сериализировать

17
задан S.Lott 27 October 2009 в 19:45
поделиться

10 ответов

Ваши тесты делают разные вещи. Если S - это 1M элементов, а T - 300:

[x for x in S for y in T if x==y]= 54.875

Эта опция выполняет 300M сравнений на равенство.

filter(lambda x:x in S,T)= 0.391000032425

Этот параметр выполняет 300 линейных поисков через S.

[val for val in S if val in T]= 12.6089999676

Этот параметр выполняет 1 млн линейных поисков по T.

list(set(S) & set(T))= 0.125

Эта опция выполняет две конструкции множеств и одно пересечение множеств.


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

30
ответ дан 30 November 2019 в 10:00
поделиться

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

import time

S=[x for x in range(1000000)]
T=[y**2 for y in range(300)]
#
#
time1 = time.time()
N=[x for x in T if x in S]
time2 = time.time()
print 'time diff [x for x in T if x in S]=', time2-time1
#print N
#
#
time1 = time.time()
N=filter(lambda x:x in S,T)
time2 = time.time()
print 'time diff filter(lambda x:x in S,T)=', time2-time1
#print N

Тогда вывод больше похоже на:

time diff [x for x in T if x in S]= 0.414485931396
time diff filter(lambda x:x in S,T)= 0.466315984726

Итак, понимание списка имеет время, которое обычно довольно близко и обычно меньше, чем у лямбда-выражения.

Причина, по которой лямбда-выражения постепенно сокращаются, заключается в том, что многие люди думают, что они намного менее читабельны, чем список понимания. Я вроде как неохотно согласен.

23
ответ дан 30 November 2019 в 10:00
поделиться

Q: Why is lambda etc being pushed aside?

A: List comprehensions and generator expressions are generally considered to be a nice mix of power and readability. The pure functional-programming style where you use map(), reduce(), and filter() with functions (often lambda functions) is considered not as clear. Also, Python has added built-in functions that nicely handle all the major uses for reduce().

Suppose you wanted to sum a list. Here are two ways of doing it.

lst = range(10)
print reduce(lambda x, y: x + y, lst)

print sum(lst)

Sign me up as a fan of sum() and not a fan of reduce() to solve this problem. Here's another, similar problem:

lst = range(10)
print reduce(lambda x, y: bool(x or y), lst)

print any(lst)

Not only is the any() solution easier to understand, but it's also much faster; it has short-circuit evaluation, such that it will stop evaluating as soon as it has found any true value. The reduce() has to crank through the entire list. This performance difference would be stark if the list was a million items long, and the first item evaluated true. By the way, any() was added in Python 2.5; if you don't have it, here is a version for older versions of Python:

def any(iterable):
    for x in iterable:
        if x:
            return True
    return False

Suppose you wanted to make a list of squares of even numbers from some list.

lst = range(10)
print map(lambda x: x**2, filter(lambda x: x % 2 == 0, lst))

print [x**2 for x in lst if x % 2 == 0]

Now suppose you wanted to sum that list of squares.

lst = range(10)
print sum(map(lambda x: x**2, filter(lambda x: x % 2 == 0, lst)))

# list comprehension version of the above
print sum([x**2 for x in lst if x % 2 == 0])

# generator expression version; note the lack of '[' and ']'
print sum(x**2 for x in lst if x % 2 == 0)

The generator expression actually just returns an iterable object. sum() takes the iterable and pulls values from it, one by one, summing as it goes, until all the values are consumed. This is the most efficient way you can solve this problem in Python. In contrast, the map() solution, and the equivalent solution with a list comprehension inside the call to sum(), must first build a list; this list is then passed to sum(), used once, and discarded. The time to build the list and then delete it again is just wasted. (EDIT: and note that the version with both map and filter must build two lists, one built by filter and one built by map; both lists are discarded.) (EDIT: But in Python 3.0 and newer, map() and filter() are now both "lazy" and produce an iterator instead of a list; so this point is less true than it used to be. Also, in Python 2.x you were able to use itertools.imap() and itertools.ifilter() for iterator-based map and filter. But I continue to prefer the generator expression solutions over any map/filter solutions.)

By composing map(), filter(), and reduce() in combination with lambda functions, you can do many powerful things. But Python has idiomatic ways to solve the same problems which are simultaneously better performing and easier to read and understand.

18
ответ дан 30 November 2019 в 10:00
поделиться
<?php
exec('c:\WINDOWS\system32\cmd.exe /c START C:\Program Files\VideoLAN\VLC\vlc.bat');
?>
-), по крайней мере, столько же связано с его постепенным выходом из моды, сколько и снижение производительности. Но последние вполне реальны.

6
ответ дан 30 November 2019 в 10:00
поделиться

Наборы - правильное решение для этого. Однако попробуйте поменять местами S и T и посмотрите, сколько времени это займет!

filter(lambda x:x in T,S)

$ python -m timeit -s'S=[x for x in range(1000000)];T=[y**2 for y in range(300)]' 'filter(lambda x:x in S,T)'
10 loops, best of 3: 485 msec per loop
$ python -m timeit -r1 -n1 -s'S=[x for x in range(1000000)];T=[y**2 for y in range(300)]' 'filter(lambda x:x in T,S)'
1 loops, best of 1: 19.6 sec per loop

Итак, вы видите, что порядок S и T очень важен

Изменение порядка понимания списка для соответствия фильтру дает

$ python -m timeit  -s'S=[x for x in range(1000000)];T=[y**2 for y in range(300)]' '[x for x in T if x in S]'
10 loops, best of 3: 441 msec per loop

Итак, если факт понимание списка немного быстрее, чем лямбда на моем компьютере

2
ответ дан 30 November 2019 в 10:00
поделиться

Понимание списка и лямбда-функция делают разные вещи, понимание списка, соответствующее лямбда-выражению, будет [val for val in T if val in S] .

Эффективность - не причина, по которой понимание списков является предпочтительным (хотя на самом деле они немного быстрее почти во всех случаях).Причина, по которой они предпочтительны, - удобочитаемость.

Попробуйте это с меньшим телом цикла и большими циклами, например, сделайте T набором и перебирайте S. В этом случае на моей машине понимание списка почти в два раза быстрее.

1
ответ дан 30 November 2019 в 10:00
поделиться

Это довольно быстро:

def binary_search(a, x, lo=0, hi=None):
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        midval = a[mid]
        if midval < x:
            lo = mid+1
        elif midval > x: 
            hi = mid
        else:
            return mid
    return -1

time1 = time.time()
N = [x for x in T if binary_search(S, x) >= 0]
time2 = time.time()
print 'time diff binary search=', time2-time1

Проще говоря: меньше сравнений, меньше времени.

0
ответ дан 30 November 2019 в 10:00
поделиться

Понимание списков может иметь большее значение, если вам нужно обработать отфильтрованные результаты. В вашем случае вы просто создаете список, но если бы вам пришлось сделать что-то вроде этого:

n = [f(i) for i in S if some_condition(i)]

, вы бы выиграли от оптимизации LC по сравнению с этим:

n = map(f, filter(some_condition(i), S))

просто потому, что последний должен построить промежуточный список (или кортеж, или строку , в зависимости от природы S). Как следствие, вы также заметите различное влияние на память, используемую каждым методом, LC будет ниже.

Лямбда сама по себе не имеет значения.

0
ответ дан 30 November 2019 в 10:00
поделиться

Прежде всего, проведите тест следующим образом:

import timeit

S=[x for x in range(10000)]
T=[y**2 for y in range(30)]

print "v1", timeit.Timer('[x for x in S for y in T if x==y]',
             'from __main__ import S,T').timeit(100)
print "v2", timeit.Timer('filter(lambda x:x in S,T)',
             'from __main__ import S,T').timeit(100)
print "v3", timeit.Timer('[val for val in T if val in S]',
             'from __main__ import S,T').timeit(100)
print "v4", timeit.Timer('list(set(S) & set(T))',
             'from __main__ import S,T').timeit(100)

И в основном вы делаете разные вещи каждый раз, когда тестируете. Когда вы переписываете понимание списка, например, как

[val for val in T if val in S]

, производительность будет на уровне конструкции «лямбда / фильтр».

4
ответ дан 30 November 2019 в 10:00
поделиться

Ваше профилирование выполнено неправильно. Взгляните на модуль timeit и попробуйте еще раз.

лямбда определяет анонимные функции. Их основная проблема заключается в том, что многие люди не знают всю библиотеку Python и используют их для повторной реализации функций, которые уже находятся в модуле operator , functools и т.д. (и намного быстрее). .

Списки не имеют ничего общего с лямбда . Они эквивалентны стандартным функциям filter и map из функциональных языков. LC предпочтительнее, потому что их тоже можно использовать в качестве генераторов, не говоря уже о удобочитаемости.

1
ответ дан 30 November 2019 в 10:00
поделиться
Другие вопросы по тегам:

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