अजगर सूची समझ का उपयोग कर एक शर्त के आधार पर तत्वों के सूचकांक का पता लगाना


119

Matlab बैकग्राउंड से आने पर निम्नलिखित पायथन कोड बहुत लंबे वाइंडेड प्रतीत होते हैं

>>> a = [1, 2, 3, 1, 2, 3]
>>> [index for index,value in enumerate(a) if value > 2]
[2, 5]

जब मतलब में मैं लिख सकता हूँ:

>> a = [1, 2, 3, 1, 2, 3];
>> find(a>2)
ans =
     3     6

क्या पायथन में इसे लिखने का एक छोटा हाथ तरीका है, या मैं सिर्फ लंबे संस्करण के साथ रहना चाहता हूं?


अजगर के वाक्य विन्यास के लिए तर्क के सभी सुझावों और स्पष्टीकरण के लिए धन्यवाद।

सुन्न वेबसाइट पर निम्नलिखित खोजने के बाद, मुझे लगता है कि मुझे एक समाधान मिला है जो मुझे पसंद है:

http://docs.scipy.org/doc/numpy/user/basics.indexing.html#boolean-or-mask-index-arrays

उस वेबसाइट की जानकारी को ऊपर मेरी समस्या पर लागू करना, निम्नलिखित देगा:

>>> from numpy import array
>>> a = array([1, 2, 3, 1, 2, 3])
>>> b = a>2 
array([False, False, True, False, False, True], dtype=bool)
>>> r = array(range(len(b)))
>>> r(b)
[2, 5]

निम्नलिखित को तब काम करना चाहिए (लेकिन मुझे इसका परीक्षण करने के लिए हाथ पर पायथन दुभाषिया नहीं मिला है):

class my_array(numpy.array):
    def find(self, b):
        r = array(range(len(b)))
        return r(b)


>>> a = my_array([1, 2, 3, 1, 2, 3])
>>> a.find(a>2)
[2, 5]

6
कैसे के बारे में [idx for idx in range(len(a)) if a[idx] > 2]? पायथन में ऐसा करने का कारण थोड़ा अजीब है क्योंकि यह अन्य भाषाओं की तरह अनुक्रमित का उपयोग नहीं करता है।
NullUserException

जवाबों:


77
  • पायथन में, आप इसके लिए सभी अनुक्रमित का उपयोग नहीं करेंगे, लेकिन बस मूल्यों से निपटें- [value for value in a if value > 2]। आमतौर पर अनुक्रमित से निपटने का मतलब है कि आप कुछ सबसे अच्छा तरीका नहीं कर रहे हैं।

  • यदि आप करते हैं मैटलैब के लिए इसी तरह की एक API की जरूरत है, आप का प्रयोग करेंगे numpy बहुआयामी सरणियों और अजगर में संख्यात्मक गणित जो काफी हद तक मैटलैब से प्रेरित है के लिए एक पैकेज,। आप एक सूची के बजाय एक संख्यात्मक सरणी का उपयोग कर रहे होंगे।

    >>> import numpy
    >>> a = numpy.array([1, 2, 3, 1, 2, 3])
    >>> a
    array([1, 2, 3, 1, 2, 3])
    >>> numpy.where(a > 2)
    (array([2, 5]),)
    >>> a > 2
    array([False, False,  True, False, False,  True], dtype=bool)
    >>> a[numpy.where(a > 2)]
    array([3, 3])
    >>> a[a > 2]
    array([3, 3])

2
आपके पास सूचियाँ हैं, श्रेणियों के लिए एक और कोणों के लिए, आप श्रेणी मानों को फ़िल्टर करना चाहते हैं जो कुछ सीमा से ऊपर हैं। आप "सर्वश्रेष्ठ तरीके से" फैशन में उन श्रेणियों के अनुरूप कोणों को कैसे फ़िल्टर करते हैं?
मेहदी

3
filtered_ranges_and_angles = [(range, angle) for range, angle in zip(ranges, angles) if should_be_kept(range)]
माइक ग्राहम

7
"पायथन में, आप इसके लिए सभी अनुक्रमित का उपयोग नहीं करेंगे, लेकिन बस मूल्यों के साथ व्यवहार करें" यह कथन दर्शाता है कि आपने पर्याप्त डेटा विश्लेषण और मशीन लर्निंग मॉडलिंग नहीं किया है। कुछ शर्तों के आधार पर एक टेंसर के संकेत दूसरे टेंसर को फ़िल्टर करने के लिए उपयोग किए जाते हैं।
राशिफल

63

दूसरा रास्ता:

>>> [i for i in range(len(a)) if a[i] > 2]
[2, 5]

सामान्य तौर पर, तो याद रखें कि जबकि findएक तैयार पकाया समारोह है, सूची comprehensions एक सामान्य, और इस प्रकार बहुत शक्तिशाली समाधान कर रहे हैं । कुछ भी आपको findपायथन में एक फ़ंक्शन लिखने से रोकता है और बाद में इसे अपनी इच्छानुसार उपयोग करें। अर्थात:

>>> def find_indices(lst, condition):
...   return [i for i, elem in enumerate(lst) if condition(elem)]
... 
>>> find_indices(a, lambda e: e > 2)
[2, 5]

ध्यान दें कि मैं यहां Matlab की नकल करने के लिए सूचियों का उपयोग कर रहा हूं। जनरेटर और पुनरावृत्तियों का उपयोग करना अधिक पायथोनिक होगा।


2
इसके [i for i,v in enumerate(a) if v > 2]बजाय ओपी ने लिखा हो सकता है ।
NullUserException

यह छोटा नहीं है, यह लंबा है। के indexसाथ बदलें iऔरvalue साथ vमूल में और वर्ण गिनती।
एएफएफ

@NullUser, agf: आप सही कह रहे हैं, लेकिन मुख्य बिंदु दूसरा भाग है :)
एली बेंडरस्की

1
enumerateओवर range(len(...))का उपयोग करना अधिक मजबूत और अधिक कुशल दोनों है।
माइक ग्राहम

1
@ माइक ग्राहम: मैं सहमत हूँ - find_indicesउपयोग करने के लिए तेह फ़ंक्शन को बदल देगाenumerate
एली बेंडस्काई


6

हो सकता है कि एक और सवाल यह है, "एक बार आप उन सूचकांकों के साथ क्या करने जा रहे हैं? यदि आप एक और सूची बनाने के लिए उनका उपयोग करने जा रहे हैं, तो पायथन में, वे एक अनावश्यक मध्य कदम हैं। यदि आप सभी मान चाहते हैं जो किसी दिए गए शर्त से मेल खाते हैं, तो बस बिल्टिन फ़िल्टर का उपयोग करें:

matchingVals = filter(lambda x : x>2, a)

या अपनी खुद की सूची लिखें:

matchingVals = [x for x in a if x > 2]

यदि आप उन्हें सूची से हटाना चाहते हैं, तो पाइथोनिक तरीका जरूरी नहीं है कि सूची से हटा दें, बल्कि एक सूची को लिखें जैसे कि आप एक नई सूची बना रहे हैं, और listvar[:]बाएं हाथ का उपयोग करके वापस अंदर जगह सौंप रहे हैं साइड:

a[:] = [x for x in a if x <= 2]

मतलाब आपूर्ति करता है findक्योंकि इसका सरणी-केंद्रित मॉडल उनके सरणी सूचकांकों का उपयोग करके आइटम का चयन करके काम करता है। आप पायथन में ऐसा कर सकते हैं, निश्चित रूप से, लेकिन अधिक पायथोनिक तरीका पुनरावृत्तियों और जनरेटर का उपयोग कर रहा है, जैसा कि @EliBendersky द्वारा पहले ही उल्लेख किया गया है।


पॉल, मैं अभी तक इसके लिए स्क्रिप्ट / फंक्शन / क्लास में नहीं आया हूं। यह उस वर्ग के संवादात्मक परीक्षण के लिए अधिक है जो मैं लिख रहा हूं।
ली

@ माइक - संपादन के लिए धन्यवाद, लेकिन मेरा वास्तव में मतलब था a[:] = ...- एलेक्स मार्टेली का इस सवाल का जवाब देखें stackoverflow.com/questions/1352885/…
पॉलमैक्स

@ पाओल, मैंने मान लिया (और आशा है!) आपको वास्तव में अपने विवरण से यह मतलब नहीं था कि आप "एक नई सूची बनाने जा रहे हैं"; मुझे लगता है कि जब वे मौजूदा डेटा को बहुत संयम से बदलते हैं तो कार्यक्रम समझने और बनाए रखने के लिए उत्सुक होते हैं। किसी भी घटना में, मुझे ओवरस्टेप करने के लिए खेद है - आपको निश्चित रूप से अपनी पोस्ट को वापस संपादित करने में सक्षम होना चाहिए जो आप चाहते हैं।
माइक ग्राहम

6

भले ही यह एक देर से उत्तर हो: मुझे लगता है कि यह अभी भी एक बहुत अच्छा सवाल है और IMHO पायथन (बिना अतिरिक्त पुस्तकालयों या टूलपीट्स जैसे संख्यात्मक) अभी भी मैन्युअल रूप से परिभाषित फिल्टर के अनुसार सूची तत्वों के सूचकांक तक पहुंचने के लिए एक सुविधाजनक विधि का अभाव है।

आप मैन्युअल रूप से एक फ़ंक्शन को परिभाषित कर सकते हैं, जो कि कार्यक्षमता प्रदान करता है:

def indices(list, filtr=lambda x: bool(x)):
    return [i for i,x in enumerate(list) if filtr(x)]

print(indices([1,0,3,5,1], lambda x: x==1))

पैदावार: [0, 4]

मेरी कल्पना में सही तरीका एक बच्चे की सूची बनाने और कक्षा विधि के रूप में सूचक कार्यों को जोड़ना होगा। इस तरह से केवल फ़िल्टर विधि की आवश्यकता होगी:

class MyList(list):
    def __init__(self, *args):
        list.__init__(self, *args)
    def indices(self, filtr=lambda x: bool(x)):
        return [i for i,x in enumerate(self) if filtr(x)]

my_list = MyList([1,0,3,5,1])
my_list.indices(lambda x: x==1)

मैंने यहाँ उस विषय पर थोड़ा और विस्तार किया: http://tinyurl.com/jajrr87

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