পুনরাবৃত্তযোগ্য থেকে প্রথম আইটেমটি পান যা শর্তের সাথে মেলে


303

শর্তের সাথে তাল মিলিয়ে আমি প্রথম আইটেমটি পেতে চাই। এটি গুরুত্বপূর্ণ যে ফলস্বরূপ পদ্ধতিটি পুরো তালিকায় প্রক্রিয়া না করে, যা বেশ বড় হতে পারে। উদাহরণস্বরূপ, নিম্নলিখিত ফাংশন পর্যাপ্ত:

def first(the_iterable, condition = lambda x: True):
    for i in the_iterable:
        if condition(i):
            return i

এই ফাংশনটি এরকম কিছু ব্যবহার করা যেতে পারে:

>>> first(range(10))
0
>>> first(range(10), lambda i: i > 3)
4

যাইহোক, আমি এটি করার জন্য কোনও ভাল অন্তর্নির্মিত / ওয়ান-লাইনার সম্পর্কে ভাবতে পারি না। আমি বিশেষভাবে এই ফাংশনটি অনুলিপি করতে চাই না যদি আমার না হয়। শর্তের সাথে মিল রেখে প্রথম আইটেমটি পাওয়ার কি কোনও অন্তর্নির্মিত উপায় আছে?


উত্তর:


475

পাইথন ২.6 বা আরও নতুন:

StopIterationযদি কোনও উত্সাহী উপাদান না পাওয়া যায় তবে আপনি যদি উত্থাপন করতে চান :

next(x for x in the_iterable if x > 3)

আপনি যদি default_value(উদাহরণস্বরূপ None) পরিবর্তে ফিরে আসতে চান :

next((x for x in the_iterable if x > 3), default_value)

নোট করুন যে এক্ষেত্রে জেনারেটর এক্সপ্রেশনটির চারপাশে আপনার অতিরিক্ত জোড়া বন্ধনী প্রয়োজন - যখনই জেনারেটর এক্সপ্রেশনটি একমাত্র যুক্তি না হয় সেগুলি প্রয়োজন।

আমি বেশিরভাগ উত্তরগুলি nextবিল্ট- ইনটিকে দৃ ignore়ভাবে উপেক্ষা করে দেখছি এবং তাই আমি ধরে নিয়েছি যে কোনও রহস্যজনক কারণে তারা পাইথন-সংস্করণ সমস্যার উল্লেখ না করেই 2.5% এবং তার চেয়ে বেশি বয়স্ক সংস্করণগুলিতে 100% দৃষ্টি নিবদ্ধ রেখেছেন (তবে তারপরে আমি সেই উল্লেখটি দেখতে পাচ্ছি না) উত্তরগুলি কি উল্লেখ nextবিল্ট-ইন, যার কারণে আমি ভেবেছিলাম এটা প্রয়োজনীয় একটি উত্তর নিজেকে প্রদান - অন্তত "সঠিক সংস্করণ" ইস্যু রেকর্ডে এই ভাবে ;-) পায়।

2.5 এ, পুনরাবৃত্তকারীগুলির তাত্ক্ষণিকভাবে শেষ হয়ে গেলে .next()পুনরুদ্ধারকারীগুলির পদ্ধতিটি তত্ক্ষণাত উত্থাপিত হয় StopIteration- অর্থাত্ আপনার ব্যবহারের ক্ষেত্রে, যদি পুনরাবৃত্তিযোগ্য কোনও জিনিস শর্তটিকে সন্তুষ্ট না করে। যদি আপনার পাত্তা না থাকে (যেমন, আপনি জানেন যে কমপক্ষে একটি সন্তোষজনক আইটেম থাকতে হবে) তবে কেবল ব্যবহার করুন .next()(জিনপ এক্সে সেরা, nextপাইথন ২.6-এ অন্তর্নির্মিতের জন্য লাইন এবং আরও ভাল)।

আপনি যদি না একটি ফাংশন মধ্যে যত্ন, মোড়ানো কিছু যেমন প্রথমে আপনি আপনার প্রশ্ন নির্দেশিত ছিল সেরা মনে হয়, এবং ফাংশন বাস্তবায়ন আপনি প্রস্তাবিত শুধু জরিমানা থাকাকালীন, আপনি অন্যথায় ব্যবহার করতে পারে itertools, একটি for...: breakলুপ, অথবা একটি genexp, অথবা একটি try/except StopIterationফাংশনের শরীরের হিসাবে , বিভিন্ন উত্তর হিসাবে পরামর্শ। এই বিকল্পগুলির কোনওর মধ্যে খুব বেশি সংযোজনিত মূল্য নেই তাই আমি প্রথমে প্রস্তাবিত একেবারে সহজ সংস্করণটির জন্য যেতে পারি।


6
আপনি বর্ণনা হিসাবে কাজ করে না। StopIterationকোনও
উত্স

যেহেতু এটি অনুসন্ধানের ফলাফলগুলিতে আসে, তাই আমি ২০১১ সাল থেকে @ সুরের মন্তব্য অনুসরণ করেছি এবং বিষয়গুলি আরও স্পষ্ট করতে প্রথম অনুচ্ছেদে কিছুটা উচ্চারণ করেছি। আপনার প্রয়োজন হলে দয়া করে এগিয়ে যান এবং আমার সম্পাদনাটি সংশোধন করুন।
কোস

4
যেহেতু এটি নির্বাচিত উত্তর, আমি এখানে প্রথম উপাদানটি সঠিকভাবে নির্বাচন করার জন্য একটি উত্তর ভাগ করতে বাধ্য হচ্ছি । সংক্ষেপে: পরবর্তী ব্যবহারকে উত্সাহ দেওয়া উচিত নয়।
লোকারাড

1
@ গুয়ারাড কীভাবে সমাধানটির প্রস্তাব দেওয়া হয়েছে যে কেবল উত্তর ব্যবহারের চেয়ে "ক্রিপ্টিক" কম দেওয়া হবে? পরবর্তী (এই উত্তরে) বিরুদ্ধে একমাত্র যুক্তি হ'ল আপনাকে অবশ্যই একটি ব্যতিক্রম পরিচালনা করতে হবে; সত্যি?
আব্রাহাম টিএস

আমার মন্তব্যটি মন্তব্যটি লেখার সময়ের চেয়ে কিছুটা আলাদা। আমি আপনার পয়েন্ট দেখুন. বলা হচ্ছে, হ্যান্ডেল StopIterationকরা সত্যিই সুন্দর নয়। একটি পদ্ধতি ব্যবহার ভাল।
26:25

29

পুনরায় ব্যবহারযোগ্য, নথিভুক্ত ও পরীক্ষিত ফাংশন হিসাবে

def first(iterable, condition = lambda x: True):
    """
    Returns the first item in the `iterable` that
    satisfies the `condition`.

    If the condition is not given, returns the first item of
    the iterable.

    Raises `StopIteration` if no item satysfing the condition is found.

    >>> first( (1,2,3), condition=lambda x: x % 2 == 0)
    2
    >>> first(range(3, 100))
    3
    >>> first( () )
    Traceback (most recent call last):
    ...
    StopIteration
    """

    return next(x for x in iterable if condition(x))

ডিফল্ট যুক্তি সহ সংস্করণ

@ জারফ এই ফাংশনটির একটি সংস্করণ পরামর্শ দিয়েছিল যেখানে পুনরাবৃত্তিযোগ্য খালি থাকলে বা শর্তের সাথে মেলে এমন কোনও আইটেম না থাকলে আপনার পূর্বনির্ধারিত ফিরতি মান থাকতে পারে:

def first(iterable, default = None, condition = lambda x: True):
    """
    Returns the first item in the `iterable` that
    satisfies the `condition`.

    If the condition is not given, returns the first item of
    the iterable.

    If the `default` argument is given and the iterable is empty,
    or if it has no items matching the condition, the `default` argument
    is returned if it matches the condition.

    The `default` argument being None is the same as it not being given.

    Raises `StopIteration` if no item satisfying the condition is found
    and default is not given or doesn't satisfy the condition.

    >>> first( (1,2,3), condition=lambda x: x % 2 == 0)
    2
    >>> first(range(3, 100))
    3
    >>> first( () )
    Traceback (most recent call last):
    ...
    StopIteration
    >>> first([], default=1)
    1
    >>> first([], default=1, condition=lambda x: x % 2 == 0)
    Traceback (most recent call last):
    ...
    StopIteration
    >>> first([1,3,5], default=1, condition=lambda x: x % 2 == 0)
    Traceback (most recent call last):
    ...
    StopIteration
    """

    try:
        return next(x for x in iterable if condition(x))
    except StopIteration:
        if default is not None and condition(default):
            return default
        else:
            raise

6
আপনি যদি এটি কোনও পদ্ধতির সাথে মুড়িয়ে রাখছেন তবে কমপক্ষে স্টপআইটরেশন ধরুন এবং খালি সিকোয়েন্স ত্রুটি বাড়ান। উপাদান নেই যখন অনেক সুন্দর হতে হবে।
গেয়ারাড

@ গুয়ারাড এটি কি এক ধরণের ভ্যালুরইরর?
ক্যারিডরক

2
@ গুয়ারাড StopIterationহ'ল পাইথনের ব্যতিক্রমী "উপাদানগুলির বাইরে" exception এটি নিক্ষেপ করতে কোনও সমস্যা দেখছি না। আমি সম্ভবত "কিছুই নয়" এর একটি ডিফল্ট ব্যবহার করব যা ফাংশনে ডিফল্ট প্যারামিটার হিসাবে যেতে পারে।
বাল্ড্রিক

1
বালড্রিক এটাকে আমার মনে হচ্ছে এটি কোনও পুনরাবৃত্তি পদ্ধতি নয়। কোনও পুনরুক্তির প্রতিযোগিতায় আপনি এটিকে ডাকবেন না। তবে আমি এটি সম্পর্কে খুব
দৃ strongly়তা

1
একটি defaultচ্ছিক ডিফল্ট আর্গুমেন্ট থাকতে হবে এবং যদি সেই যুক্তি সরবরাহ না করা হয় তবে কেবল তখনই ব্যতিক্রম বাড়াতে হবে যখন ক্রমের কোনও উপাদান শর্তটি পূরণ করে না।
জোরফ

28

অভিশাপ!

আমি এই উত্তর ভালবাসি । তবে যেহেতু কোনও আইটেম নেই তখন next()একটি StopIterationব্যতিক্রম উত্থাপন করুন , আমি একটি ব্যতিক্রম এড়াতে নিম্নলিখিত স্নিপেটটি ব্যবহার করব:

a = []
item = next((x for x in a), None)

উদাহরণ স্বরূপ,

a = []
item = next(x for x in a)

StopIterationব্যতিক্রম উত্থাপন করবে ;

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

13

ব্যবহারের অনুরূপ ifilter, আপনি একটি জেনারেটর এক্সপ্রেশন ব্যবহার করতে পারেন:

>>> (x for x in xrange(10) if x > 5).next()
6

উভয় ক্ষেত্রেই, আপনি সম্ভবত ধরতে চান StopIterationযদিও কোনও উপাদান আপনার শর্তটি পূরণ না করে।

প্রযুক্তিগতভাবে বলতে গেলে, আমি মনে করি আপনি এরকম কিছু করতে পারেন:

>>> foo = None
>>> for foo in (x for x in xrange(10) if x > 5): break
... 
>>> foo
6

এটি একটি try/exceptব্লক করা এড়ানো হবে । তবে এটি সিনট্যাক্সের কাছে এক ধরণের অস্পষ্ট এবং আপত্তিজনক বলে মনে হচ্ছে।


+1: অস্পষ্ট বা আপত্তিজনক নয়। সমস্ত বিষয় বিবেচনা করা হয়, শেষটি বেশ পরিষ্কার মনে হয়।
এসলট

6
শেষটি মোটেও পরিষ্কার নয় - অ্যাসাইনমেন্টটি স্পষ্ট for foo in genex: breakনা foo = next(genex)করেই করা ব্যতীত একমাত্র উপায় এবং অপারেশনটি যদি উত্থাপিত হয় তবে অপারেশনটি স্কোয়াশেড হওয়ার কোনও মানে হয় না। ব্যতিক্রম কোড ধরা না দিয়ে ব্যর্থ কোড দিয়ে শেষ করা পাইথনের সাধারণত খারাপ জিনিস।
মাইক গ্রাহাম

13

পাইথন 3-এর সর্বাধিক দক্ষ উপায় নিম্নলিখিতগুলির মধ্যে একটি (অনুরূপ উদাহরণ ব্যবহার করে):

সঙ্গে "ধী" শৈলী:

next(i for i in range(100000000) if i == 1000)

সতর্কতা : এক্সপ্রেশনটি পাইথন 2 এর সাথেও কাজ করে, তবে উদাহরণস্বরূপ ব্যবহৃত হয় rangeযে পাইথন 2 এর মতো একটি তালিকার পরিবর্তে পাইথন 3 এ পুনরাবৃত্তিযোগ্য বস্তুর প্রত্যাবর্তন করে (আপনি যদি পাইথন 2 ব্যবহারের ক্ষেত্রে পুনরাবৃত্ত করতে চান xrange)।

নোট করুন যে বোধগম্যতা বোঝার অভিব্যক্তিতে next([i for ...])একটি তালিকা তৈরি করা এড়াতে পারে , যা উপাদানগুলিকে ফিল্টার করার আগে সমস্ত উপাদানগুলির সাথে একটি তালিকা তৈরি করতে পারে এবং একবারে পুনরাবৃত্তিটি থামানোর পরিবর্তে পুরো বিকল্পগুলি প্রক্রিয়া করতে পারে i == 1000

সঙ্গে "কার্মিক" শৈলী:

next(filter(lambda i: i == 1000, range(100000000)))

সতর্কতামূলক এই এমনকি প্রতিস্থাপন পাইথন 2 কাজ করে না, rangeসঙ্গে xrangeযে কারণে filterএকটি পুনরুক্তিকারীর (অদক্ষ) পরিবর্তে একটি তালিকা তৈরি করুন এবং nextফাংশন শুধুমাত্র iterators সাথে কাজ করে।

ডিফল্ট মান

অন্যান্য প্রতিক্রিয়াগুলিতে উল্লিখিত হিসাবে next, শর্তটি পূরণ না হয়ে আপনি যদি উত্থাপিত ব্যতিক্রম এড়াতে চান তবে আপনাকে অবশ্যই ফাংশনে একটি অতিরিক্ত-প্যারামিটার যুক্ত করতে হবে ।

"কার্যকরী" শৈলী:

next(filter(lambda i: i == 1000, range(100000000)), False)

"বোধগম্যতা" শৈলী:

()একটি এড়ানোর জন্য আপনার এই স্টাইলের সাথে বোধগম্য ভাবটি ঘিরে রাখা দরকার SyntaxError: Generator expression must be parenthesized if not sole argument:

next((i for i in range(100000000) if i == 1000), False)


6

itertoolsমডিউল iterators জন্য আপনি একটি ফিল্টার ফাংশন ধারণ করে। ফিল্টার করা পুনরুদ্ধারের প্রথম উপাদান next()এটির কল করে পাওয়া যাবে:

from itertools import ifilter

print ifilter((lambda i: i > 3), range(10)).next()

2
জেনারেটর এক্সপ্রেশন সহজ।
এরিক হে লেবিগোট

1
( i) filterএবং ( i) mapক্ষেত্রে প্রয়োগ করা ফাংশনগুলি ইতিমধ্যে বিদ্যমান রয়েছে সেগুলির জন্য ধারণা তৈরি করতে পারে তবে এর মতো পরিস্থিতিতে এটি কেবল একটি জেনারেটর এক্সপ্রেশন ব্যবহার করার জন্য আরও অনেক বেশি অর্থবোধ করে।
মাইক গ্রাহাম

এটি সেরা উত্তর। চলুন তালিকা comprehensions xahlee.info/comp/list_comprehension.html
MIT

6

পাইথনের পুরানো সংস্করণগুলির জন্য যেখানে পরবর্তী বিল্ট-ইন বিদ্যমান নেই:

(x for x in range(10) if x > 3).next()

5

ব্যবহার করে

(index for index, value in enumerate(the_iterable) if condition(value))

এক পরীক্ষা করতে পারবেন শর্ত এর মান প্রথম আইটেমের the_iterable , এবং প্রাপ্ত তার সূচক আইটেম সব নির্ণয় করা প্রয়োজন ছাড়াই the_iterable

ব্যবহারের সম্পূর্ণ এক্সপ্রেশন

first_index = next(index for index, value in enumerate(the_iterable) if condition(value))

এখানে ফার্স্ট_আইএনডেক্স উপরে আলোচিত অভিব্যক্তিতে চিহ্নিত প্রথম মানের মান ধরেছে


4

এই প্রশ্নের ইতিমধ্যে দুর্দান্ত উত্তর রয়েছে। আমি কেবল আমার দুটি সেন্ট যুক্ত করছি কারণ আমি আমার নিজের সমস্যার সমাধান খোঁজার চেষ্টা করে এখানে নেমেছি, যা ওপি এর সাথে খুব মিল।

আপনি যদি জেনারেটর ব্যবহার করে কোনও মানদণ্ডের সাথে মেলে প্রথম আইটেমের আইএনএডএক্স খুঁজে পেতে চান, আপনি কেবল তা করতে পারেন:

next(index for index, value in enumerate(iterable) if condition)


0

আপনি এটি ব্যবহার করতে পারেন argwhere নিম্পিতে ফাংশনটি । উদাহরণ স্বরূপ:

i) "হেলিওর্ল্ড" এর মধ্যে প্রথম "এল" খুঁজুন:

import numpy as np
l = list("helloworld") # Create list
i = np.argwhere(np.array(l)=="l") # i = array([[2],[3],[8]])
index_of_first = i.min()

ii) প্রথম এলোমেলো সংখ্যা> 0.1

import numpy as np
r = np.random.rand(50) # Create random numbers
i = np.argwhere(r>0.1)
index_of_first = i.min()

iii) সর্বশেষ এলোমেলো সংখ্যা> 0.1

import numpy as np
r = np.random.rand(50) # Create random numbers
i = np.argwhere(r>0.1)
index_of_last = i.max()

-1

পাইথন 3 এ:

a = (None, False, 0, 1)
assert next(filter(None, a)) == 1

পাইথন ২.6 এ:

a = (None, False, 0, 1)
assert next(iter(filter(None, a))) == 1

সম্পাদনা: আমি ভেবেছিলাম এটি সুস্পষ্ট, তবে দৃশ্যত নয়: পরিবর্তে Noneআপনি lambdaশর্তটি পরীক্ষা করে কোনও ফাংশন (বা ক ) পাস করতে পারবেন :

a = [2,3,4,5,6,7,8]
assert next(filter(lambda x: x%2, a)) == 3

-3

এক রৈখিক:

thefirst = [i for i in range(10) if i > 3][0]

যদি আপনি নিশ্চিত না হন যে কোনও উপাদান মানদণ্ড অনুসারে বৈধ হবে, তবে আপনার এটি আবদ্ধ করা উচিত try/exceptযেহেতু এটি [0]কোনও বাড়াতে পারে IndexError


প্রকারের ত্রুটি: 'জেনারেটর' অবজেক্টটি আনসস্ক্রিপ্টযোগ্য
জোশ লি

আমার খারাপ, তালিকা বোধগম্য হওয়া উচিত জেনারেটর নয়, স্থির ... ধন্যবাদ! :)
মিজিপজোর

2
পুরো পুনরাবৃত্তের মূল্যায়ন করার কোনও কারণ নেই (যা সম্ভব নাও হতে পারে)। প্রদত্ত অন্যান্য সমাধানগুলির মধ্যে একটি ব্যবহার করা এটি আরও দৃust় এবং দক্ষ।
মাইক গ্রাহাম
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.