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] 

Есть ли более элегантный и «питонический» способ?

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

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

Другой метод:

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

Не огромное улучшение:

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

Вероятно, он не так хорош, как другие ответы в этом случае, но если он используется как часть большей базы кода, может быть полезно определить итератор, который возвращает пары элементов над списком, например:

 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])] 

Это не однострочный, но вполне читаемый.

Если вы счастливы использовать numpy …

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

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

Или вы можете построить его numpy.roll используя 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 

Объединение ответа с icecrime с этим ответом дает еще одну питоническую возможность:

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