2013-04-30 2 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] 

Есть ли более элегантный и «вещий» путь?

ответ

3

Я бы сказал, что это небольшое улучшение. Там вполне может быть чище, чем путь этого, хотя:

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

Гораздо более элегантно, чем я! Использование модуля вместо trinary if/else велик. – HennyH

0

Если вы счастливы использовать NumPy ...

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

Это хорошо масштабируется с более l. Не преобразование в список или из списка ускорит работу совсем немного (очень часто в любом случае можно использовать массив numpy вместо списка).

Или вы можете построить его самостоятельно, вы с помощью 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

+1

@ HennnyH - да только что понял :) та. – sje397

+0

Я тогда редактировал ваш (чтобы исправить ошибку), пришел к тому же выражению, что и у вас сейчас :) – HennyH

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 предоставляет другой вещий возможность:

print [numpy.linalg.norm(a-b) for a, b in zip(l, l[1:] + l[:-1])] 
Смежные вопросы