किसी सूची के तत्वों के बीच अंतर खोजना


113

संख्याओं की एक सूची को देखते हुए, हर ( i) और उसके तत्वों ( ) -थ के बीच अंतर कैसे पता चलता है i+1?

क्या एक lambdaअभिव्यक्ति या शायद एक सूची समझ का उपयोग करना बेहतर है ?

उदाहरण के लिए:

एक सूची को देखते हुए t=[1,3,6,...], लक्ष्य एक सूची मिल रहा है v=[2,3,...]क्योंकि 3-1=2, 6-3=3आदि

जवाबों:


154
>>> t
[1, 3, 6]
>>> [j-i for i, j in zip(t[:-1], t[1:])]  # or use itertools.izip in py2k
[2, 3]

14
यदि आपको पूर्ण मतभेदों की आवश्यकता है, तो [abs(j-i) for i,j in zip(t, t[1:])]
अनिल

मामले में आप इसे और अधिक कुशल बनाना चाहते हैं: list(itertools.starmap(operator.sub, zip(t[1:], t)))(आयात करने के बाद itertoolsऔर operator)।
ब्लश करना

3
असल में बस list(map(operator.sub, t[1:], t[:-1]))करेंगे।
धमाका

प्रतिभाशाली! मुझे यह जवाब बहुत पसंद है!
चायम फ्राइडमैन

104

अन्य उत्तर सही हैं, लेकिन यदि आप संख्यात्मक कार्य कर रहे हैं, तो आप शायद विचार करना चाहें। सुन्न का उपयोग करना, उत्तर है:

v = numpy.diff(t)

बहुत मददगार! धन्यवाद! np.diff([2,4,9])होगा[2,5]
TravelTrader

क्या यह zipसंस्करण की तुलना में अधिक कुशल होगा ?
user760900

35

यदि आप उपयोग नहीं करना चाहते हैं numpyऔर न ही zip, आप निम्न समाधान का उपयोग कर सकते हैं:

>>> t = [1, 3, 6]
>>> v = [t[i+1]-t[i] for i in range(len(t)-1)]
>>> v
[2, 3]

12

आप परिणाम का कुशलता से उपयोग itertools.teeऔर zipनिर्माण कर सकते हैं :

from itertools import tee
# python2 only:
#from itertools import izip as zip

def differences(seq):
    iterable, copied = tee(seq)
    next(copied)
    for x, y in zip(iterable, copied):
        yield y - x

या itertools.isliceइसके बजाय का उपयोग कर :

from itertools import islice

def differences(seq):
    nexts = islice(seq, 1, None)
    for x, y in zip(seq, nexts):
        yield y - x

आप itertoolsमॉड्यूल का उपयोग करने से भी बच सकते हैं :

def differences(seq):
    iterable = iter(seq)
    prev = next(iterable)
    for element in iterable:
        yield element - prev
        prev = element

यदि आप सभी परिणामों को संग्रहीत करने और अनंत पुनरावृत्तियों का समर्थन करने की आवश्यकता नहीं है, तो ये सभी समाधान निरंतर स्थान में काम करते हैं।


यहाँ समाधान के कुछ सूक्ष्म मानक हैं:

In [12]: L = range(10**6)

In [13]: from collections import deque
In [15]: %timeit deque(differences_tee(L), maxlen=0)
10 loops, best of 3: 122 ms per loop

In [16]: %timeit deque(differences_islice(L), maxlen=0)
10 loops, best of 3: 127 ms per loop

In [17]: %timeit deque(differences_no_it(L), maxlen=0)
10 loops, best of 3: 89.9 ms per loop

और अन्य प्रस्तावित समाधान:

In [18]: %timeit [x[1] - x[0] for x in zip(L[1:], L)]
10 loops, best of 3: 163 ms per loop

In [19]: %timeit [L[i+1]-L[i] for i in range(len(L)-1)]
1 loops, best of 3: 395 ms per loop

In [20]: import numpy as np

In [21]: %timeit np.diff(L)
1 loops, best of 3: 479 ms per loop

In [35]: %%timeit
    ...: res = []
    ...: for i in range(len(L) - 1):
    ...:     res.append(L[i+1] - L[i])
    ...: 
1 loops, best of 3: 234 ms per loop

ध्यान दें कि:

  • zip(L[1:], L)पहले zip(L[1:], L[:-1])से zipही कम से कम इनपुट पर समाप्त होने के बराबर है , हालांकि यह पूरी नकल से बचा जाता है L
  • इंडेक्स द्वारा एकल तत्वों तक पहुंच बहुत धीमी है क्योंकि हर इंडेक्स एक्सेस अजगर में एक विधि कॉल है
  • numpy.diffयह धीमा है क्योंकि इसे पहले a में बदलना listहै ndarray। जाहिर है अगर आप इसके साथ शुरू करते हैं तो ndarrayयह बहुत तेज होगा:

    In [22]: arr = np.array(L)
    
    In [23]: %timeit np.diff(arr)
    100 loops, best of 3: 3.02 ms per loop

दूसरे समाधान में, islice(seq, 1, None)इसके बजाय islice(seq, 1, len(seq))यह अनंत पुनरावृत्तियों के साथ काम करता है
ब्राह्म स्नाइडर

5

:=पाइथन 3.8+ में उपलब्ध वालरस ऑपरेटर का उपयोग करना :

>>> t = [1, 3, 6]
>>> prev = t[0]; [-prev + (prev := x) for x in t[1:]]
[2, 3]

5

मैं उपयोग करने का सुझाव दूंगा

v = np.diff(t)

यह सरल और पढ़ने में आसान है।

लेकिन अगर आप चाहते हैं vके रूप में ही लंबाई के लिए tतो

v = np.diff([t[0]] + t) # for python 3.x

या

v = np.diff(t + [t[-1]])

FYI करें: यह केवल सूचियों के लिए काम करेगा।

सुन्न सरणियों के लिए

v = np.diff(np.append(t[0], t))

अच्छा उत्तर, आप एक ही लंबाई सुनिश्चित करने के लिए प्रीपेंड कीवर्ड का उपयोग भी कर सकते हैं, नीचे उत्तर देखें, जो मुझे लगता है कि एक छोटा सा मामला है
एड्रियन टोमकिन्स

4

एक कार्यात्मक दृष्टिकोण:

>>> import operator
>>> a = [1,3,5,7,11,13,17,21]
>>> map(operator.sub, a[1:], a[:-1])
[2, 2, 2, 4, 2, 4, 4]

जनरेटर का उपयोग करना:

>>> import operator, itertools
>>> g1,g2 = itertools.tee((x*x for x in xrange(5)),2)
>>> list(itertools.imap(operator.sub, itertools.islice(g1,1,None), g2))
[1, 3, 5, 7]

सूचकांकों का उपयोग करना:

>>> [a[i+1]-a[i] for i in xrange(len(a)-1)]
[2, 2, 2, 4, 2, 4, 4]

ऑपरेटर विधि अच्छी और सुरुचिपूर्ण है
bcattle

3

ठीक। मुझे लगता है कि मुझे उचित समाधान मिला:

v = [x[1]-x[0] for x in zip(t[1:],t[:-1])]

2
फिर इसका अच्छा है, लेकिन मुझे लगता है कि यह ज़िप में x के लिए v = [x [0] -x [1] होना चाहिए (t [१:], t [: १]]] क्रमबद्ध सूची के लिए!
अमित कार्णिक

0

आवधिक सीमाओं के साथ समाधान

कभी-कभी संख्यात्मक एकीकरण के साथ आप आवधिक सीमा स्थितियों के साथ एक सूची में अंतर करना चाहेंगे (इसलिए पहला तत्व अंतिम के अंतर की गणना करता है। इस मामले में numpy.roll फ़ंक्शन सहायक है:

v-np.roll(v,1)

शून्य के साथ समाधान तैयार किए गए

एक और खस्ता समाधान (पूर्णता के लिए) का उपयोग करना है

numpy.ediff1d(v)

यह numpy.diff के रूप में काम करता है, लेकिन केवल एक वेक्टर पर (यह इनपुट सरणी को समतल करता है)। यह परिणामी वेक्टर को संख्याओं को प्रीपेन्ड या अपेंड करने की क्षमता प्रदान करता है। संचित क्षेत्रों को संभालते समय यह उपयोगी होता है जो अक्सर मौसम संबंधी चर (जैसे बारिश, अव्यक्त गर्मी आदि) में प्रवाह होता है, जैसा कि आप इनपुट चर के समान लंबाई की एक परिणामी सूची चाहते हैं, पहली प्रविष्टि के साथ।

तब आप लिखेंगे

np.ediff1d(v,to_begin=v[0])

बेशक, आप इसे np.diff कमांड के साथ भी कर सकते हैं, इस मामले में हालांकि आपको प्रीपेन्ड कीवर्ड के साथ श्रृंखला में शून्य को प्रस्तुत करने की आवश्यकता है:

np.diff(v,prepend=0.0) 

उपरोक्त सभी समाधान एक वेक्टर को वापस करते हैं जो इनपुट के समान लंबाई है।


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.