2013-04-30 30 views
4

嗨我需要計算列表中每個數字對之間的距離,包括最後一個和第一個(它是一個圓圈)之間的距離。Python:找到列表字段之間的距離

天真,我可以做這樣的事情:

l = [10,-12,350] 
ret = [] 
for i in range(len(l)-1): 
    ret.append(abs(l[i] - l[i+1])) 
ret.append(l[-1] - l[0]) 
print ret 

out: [22, 362, 340] 

我想「列舉」,這是一個更好一點的方法:

print [abs(v - (l+[l[0]])[i+1]) for i, v in enumerate(l)] 
out: [22, 362, 340] 

是否有更優雅,更「Python化」的方式?

回答

3

我認爲這是一個小改進。也很可能比這雖然是乾淨的方式:

print [abs(v - l[(i+1)%len(l)]) for i, v in enumerate(l)] 
+0

更優雅的比我早!使用模數而不是三元if/else很好。 – HennyH 2013-04-30 13:56:44

0

如果你樂於使用numpy的...

list(numpy.abs(numpy.ediff1d(l, to_end=l[0]-l[-1]))) 

這較長的l很好地擴展。不從一個列表轉換或從一個列表轉換會加速很多事情(無論如何,通常可以使用一個numpy數組代替列表)。

或者你可以youself使用numpy.roll構造它:

list(numpy.abs(l - numpy.roll(l, -1))) 

幾個時段:

In [37]: l = list(numpy.random.randn(1000)) 

In [38]: timeit [abs(v - l[(i+1)%len(l)]) for i, v in enumerate(l)] 
1000 loops, best of 3: 936 us per loop 

In [39]: timeit list(numpy.abs(numpy.ediff1d(l, to_end=l[0]-l[-1]))) 
1000 loops, best of 3: 367 us per loop 

In [40]: _l = numpy.array(l) 

In [41]: timeit numpy.abs(numpy.ediff1d(_l, to_end=l[0]-l[-1])) 
10000 loops, best of 3: 48.9 us per loop 

In [42]: timeit _l = numpy.array(l); list(numpy.abs(_l - numpy.roll(_l, -1))) 
1000 loops, best of 3: 350 us per loop 

In [43]: timeit numpy.abs(_l - numpy.roll(_l, -1)) 
10000 loops, best of 3: 32.2 us per loop 

如果原始速度是你的事,快還,但不是那麼整齊,您可以用切片直接陣列:

In [78]: timeit a = numpy.empty(_l.shape, _l.dtype); a[:-1] = _l[:-1] - _l[1:]; a[-1] = _l[-1] - _l[0]; a = numpy.abs(a) 
10000 loops, best of 3: 20.5 us per loop 
1

不是一個巨大的改進:

>>> [abs(a - b) for a, b in zip(l, l[1:] + l[:-1])] 
[22, 362, 340] 
2

另一種方法:

print map(lambda x,y: abs(x-y), l[1:] + l[:1], l) 
+0

您需要計算距離(標量),這會給出一個向量。 – HennyH 2013-04-30 14:00:18

+1

@HennnyH - 是的,只是意識到:) ta。 – sje397 2013-04-30 14:02:39

+0

我剛剛在編輯你的(嘗試修復),到達現在的相同表情:) – HennyH 2013-04-30 14:03:14

0

它可能不是在這種情況下,其他的答案是好的,但是,如果作爲一個更大的代碼庫的一部分,它可能是有用的定義,它返回對迭代器項目在列表中,例如:

def pairs(l): 
    if len(l) < 2: 
     return 

    for i in range(len(l)-1): 
     yield l[i], l[i+1] 

    yield l[-1], l[0] 

print [abs(a - b) for a,b in pairs([10,-12,350])] 

它不是一行代碼,但是相當可讀。

0

從icecrime與this answer結合的答案提供了另一種可能性,Python的:

print [numpy.linalg.norm(a-b) for a, b in zip(l, l[1:] + l[:-1])]