문제

큰 정수 목록을 Bigtable (DB)에 저장해야합니다. 효율성을 위해 나는 2 개의 연속 항목 사이에 차이로 저장하고 있습니다.

예를 들어 :

 original_list = [1005, 1004, 1003, 1004, 1006] 

위의 목록 (실제로 1000k 이상의 항목이 포함 된)을

start = 1005
diff = [-1, -1, 1, 2]

내가 관리 할 수있는 가장 가까운 것은

ltp = [start]
map(lambda x: ltp.append(ltp[-1] + x), tick)

원래 목록으로 다시 변환하는 효율적인 방법을 찾고 있습니다.

도움이 되었습니까?

해결책

다음은 저를 위해 작동합니다.

orig = [start]
for x in diff:
    orig.append(orig[-1] + x)

사용 map 동일한 크기의 새로운 배열을 만들 것입니다. None. 나는 또한 간단한 것을 발견했다 for 더 읽기 쉽고이 경우 가능한 한 빨리 고리하십시오.

다른 팁

이러한 큰 데이터 구조의 경우 Numpy는 잘 작동합니다. 이 예에서는 그렇습니다 200 배 이상 더 빠릅니다 (아래 참조), 기본적으로 코딩하기가 조금 더 쉽습니다.

add.accumulate(diff)

Numpy와 직접 목록 조작의 비교 :

import numpy as nx
import timeit

N = 10000

diff_nx = nx.zeros(N, dtype=nx.int)
diff_py = list(diff_nx)

start = 1005

def f0():
    orig = [start]
    for x in diff_py: 
        orig.append(orig[-1] + x)

def f1():
    diff_nx[0] = start
    nx.add.accumulate(diff_nx)

t = timeit.Timer("f0()", "from __main__ import f0, f1, diff_nx, diff_py, nx, start")
print t.timeit(number=1000)
t = timeit.Timer("f1()", "from __main__ import f0, f1, diff_nx, diff_py, nx, start")
print t.timeit(number=1000)

주어진

13.4044158459     # for list looping
0.0474112033844   # for numpy accumulate

그러나 실제로, 확립 된 압축 알고리즘을 재사용하는 것이 더 나은 것 같습니다. pytables, 당신이 여기서하고있는 것처럼 자신의 것을 굴리는 것보다는

또한, 여기에서, 나는 당신이 선불 시작 기간을위한 공간이있는 데이터를 읽는 것을 제안합니다. 물론 선불 용어로 목록을 재구성하기보다는 사본을 수행 할 필요가 없습니다.

발전기에 적합 :

def diff2abs( diffs, start ):
    yield start
    for diff in diffs:
        start += diff
        yield start

start = 1005
diffs = [-1, -1, 1, 2]
original_list = list( diff2abs( diffs, start ))

다른 응답자 중 일부는 귀하가 요청한 알고리즘의 합리적인 구현을 가지고 있지만, 실제로 해결하려는 문제에 대해 정확히 불분명합니다.

저장된 숫자가 매우 크지 않으면 (즉, 정수를 넘어서서, bignums을 요구 함), diffs 목록은 효율성을 얻지 못합니다. 정수는 Python 런타임 POV의 정수이므로 "diff"목록입니다. 의 [-1, -1, 1, 2] 원래 목록만큼 많은 메모리를 소비합니다. [1005, 1004, 1003, 1004, 1006].

class runningtotal:
    def __init__(self, start = 0):
        self.total = start
    def __call__(self, value):
        self.total += value
        return self.total

이제 시도하십시오 :

>>> map(runningtotal(start), [0,]+diff)
[1005, 1004, 1003, 1004, 1006]

MSHSAYEM이 제안한 바와 같이, 목록 이해력을 사용하십시오. 일반적으로 루프 나지도/람다보다 더 빠릅니다 (Mark Lutz의 책 학습 Python에 따르면).

더 많은 FP-ISH 솔루션을 사용하려면 적절한 기능은 "스캔"입니다. Wich [나는]가 Python에서 구현되지 않으므로 직접 구현해야합니다 (어려운 작업이 아닙니다).

"스캔"은 기본적으로 감소이지만 목록을 단일 값으로 줄이는 대신 새 목록에 각 "반복"의 결과를 저장합니다.

구현하면 다음과 같은 작업을 수행 할 수 있습니다.

scan(lambda x,y: x+y, [start]++diff)

왜 이것이 더 효율적이어야하는지 알지 못하지만 루프가 최상의 성능을 줄 것이라고 확신합니다.

l = [start]
for i in diff:
    l.append(l[-1] + i)

정수를 차이로 저장 한 것에 대한 당신의 추론에 대해 잘 모르겠습니다. Rcoder는 왜 이것이 정수 자체를 저장하는 것보다 일반적으로 더 효율적이지 않은지에 대한 좋은 답변을 제공했지만 전체 목록에 액세스 할 필요가 없다면 한 번에 발전기를 사용하는 것이 더 효율적입니다. 이것이 "큰 목록"이라고 말하면 한 번에 전체 목록을 할당하는 대신 많은 메모리를 이런 식으로 저장할 수 있습니다. 다음은 목록을 다시 얻기위한 생성기 이해력입니다.

start = 1005
def mod_start(x):
    global start
    start += x
    return start
int_generator = (mod_start(i) for i in diffs)

그런 다음 한 번에 메모리에 전체 목록을 사용하지 않고 목록과 같이 int_generator를 반복 할 수 있습니다. 그러나 발전기를 첨가하거나 슬라이스 할 수는 없지만 많은 유용한 상황에서 사용할 수 있습니다.

시작 변수가 글로벌 일 필요가 없도록 예제를 정리할 수 있습니다. mod_start 함수에 국한 될 수는 없습니다.

편집하다: 발전기를 얻기 위해 발전기 이해력을 사용할 필요는 없습니다. THC4K와 같이 수율 표현식으로 발전기 기능을 사용할 수도 있습니다. 그것은 시작 가변 범위 문제를 피하고 아마도 약간 더 깨끗 할 것입니다. 목록 () 내장 함수로 전달하여 언제든지 생성기에서 목록을 얻을 수 있습니다.

이것의 성능에 대한 의견은 없지만 여기에서 감소를 사용할 수 있습니다.

start = 1005
diffs = [-1,-1,1,2]
reduce(lambda undiffed_list, diff: undiffed_list + [undiffed_list[-1] + diff],diffs,[start])

당신이 원하는 것을 얻습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top