2015-01-27 2 views
1

я сейчас этот код для факторизации больших чисел:список понимания с несколькими заданиями

def f1(n): 
    return [[i, n//i] for i in range(1 , int(n**0.5) + 1) if n % i == 0] 

Это самая быстрая версия, которую я видел до сих пор (если есть более быстрый способ, которым я хотел бы знать о том, что, как хорошо), но мне нужен один список всех факторов без гнездования (так что я хочу что-то вроде: [factor 1, factor 2, factor 3,..., factor n-3, factor n-2, factor n-1, factor n] и т. д. Порядок не очень важен.

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

, т. Е.

def f1(n): 
    return [i, n//i for i in range(1 , int(n**0.5) + 1) if n % i == 0] 

Таким образом, у меня нет вложенного списка. Это было бы быстрее, и скорость была сущностью.

Я просмотрел документацию, и я не смог найти ни одного примера нескольких назначений.

+1

Так почему 'я,' там вообще, если вы только хотели 'п // i' фактор? –

+0

В этом случае вряд ли поможет много из-за небольшого количества обращений относительно промахов для факторов, но 'divmod' можно использовать для деления и мода в одно и то же время. – jwelsh

+1

И I, и n/I являются факторами n –

ответ

1

описаний списков велики, но иногда они не лучшее решение, в зависимости от требований для удобства чтения и скорости. Иногда просто выписывание подразумеваемого цикла for (и оператора if) является более читаемым и более быстрым.

def factors(n): 
    l = [] 
    for i in range(1, int(n**0.5)+1): 
     if n % i == 0: 
      l.append(i) 
      l.append(n//i) 
    return l 

Для небольших чисел вышеуказанная функция выполняется быстрее, чем понимание списка. При больших количествах (1 000 000 и более) функция и понимание списка равны по скорости.

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

def factors(n): 
    l = [] 
    append = l.append 
    for i in range(1, int(n**0.5)+1): 
     if n % i == 0: 
      append(i) 
      append(n//i) 
    return l 

Сравнение скорости:

In [86]: %timeit factors_list_comprehension(1000) 
100000 loops, best of 3: 7.57 µs per loop 

In [87]: %timeit factors_function(1000) 
100000 loops, best of 3: 6.24 µs per loop 

In [88]: %timeit factors_optimised_function(1000) 
100000 loops, best of 3: 5.81 µs per loop 

In [89]: %timeit factors_list_comprehension(1000000) 
10000 loops, best of 3: 111 µs per loop 

In [90]: %timeit factors_function(1000000) 
10000 loops, best of 3: 108 µs per loop 

In [91]: %timeit factors_optimised_function(1000000) 
10000 loops, best of 3: 106 µs per loop 
+0

Это удивительно ... Я понятия не имел, что вы можете кэшировать append. –

+0

Это сохранение точечных выражений за пределами жесткого цикла является стандартной формой оптимизации кода (http://www.compileroptimizations.com/category/hoisting.htm), в которой инвариант в цикле «поднимается» снаружи и оценивается только один раз, а не один раз на итерацию. Оценка местных жителей дешевле/быстрее, чем вычисление точечных выражений, особенно если выражение «x.y.z.f.g» глубокое. – PaulMcG

0

Вы можете достичь желаемого результата с помощью sum(). Например:

>>> sum([[1,6],[2,3]],[]) 
[1, 6, 2, 3] 

Мы можем определить ответ с точки зрения существующего кода:

def f2(n): 
    return sum(f1(n), []) 

Однако, будьте осторожны, что ваш код возвращает квадратный корень дважды, когда n является квадратом:

>>> f1(9) 
[[1, 9], [3, 3]] 
>>> f2(9) 
[1, 9, 3, 3] 
+1

Использование 'sum()' является наихудшим способом сгладить список списков. –

+0

Что было бы предпочтительнее? – Nayuki

+2

Это один из самых неэффективных способов сглаживания списка. Вместо этого используйте 'itertools.chain.from_iterable' вместо скорости, или вложенное понимание списка для читаемости. –

1

Использование itertools.chain:

from itertools import chain 

def f1(n): 
    return list(chain.from_iterable([i, n//i] for i in xrange(1 , int(n**0.5) + 1) if not n % i)) 

Если вам не нужен список, удалите вызов по цепочке и просто перейдите по возвращенному объекту цепочки.

Если оптимизация важно, вы должны использовать расширение и xrange:

def f1(n): 
    l = [] 
    for i in xrange(1, int(n**0.5)+1): 
     if not n % i: 
      l.extend((i,n//i)) 
    return l 
Смежные вопросы