كيف يمكنني بكفاءة تصفية حساب القيم داخل الثعبان قائمة الفهم?

StackOverflow https://stackoverflow.com/questions/130262

  •  02-07-2019
  •  | 
  •  

سؤال

الثعبان قائمة على الفهم اللغوي يجعل من السهل تصفية القيم داخل والفهم.على سبيل المثال:

result = [x**2 for x in mylist if type(x) is int]

عودة قائمة مربعات الأعداد في قائمتي.ومع ذلك ، ما إذا كان الاختبار ينطوي على بعض (مكلفة) حساب تريد تصفية على النتيجة ؟ خيار واحد هو:

result = [expensive(x) for x in mylist if expensive(x)]

هذا سيؤدي في قائمة غير"كاذبة" مكلفة(x) القيم غير مكلفة() يسمى مرتين لكل x.هل هناك فهم الجملة التي تسمح لك أن تفعل هذا الاختبار فقط ، بينما يدعو غالية مرة واحدة في x ؟

هل كانت مفيدة؟

المحلول

إذا كانت الحسابات بالفعل بشكل جيد المجمعة في الوظائف ، حول كيفية استخدام filter و map?

result = filter (None, map (expensive, mylist))

يمكنك استخدام itertools.imap إذا كانت القائمة كبيرة جدا.

نصائح أخرى

جاء مع بلدي الجواب بعد دقيقة من التفكير.ويمكن أن يتم ذلك مع المتداخلة comprehensions:

result = [y for y in (expensive(x) for x in mylist) if y]

أعتقد أن تعمل ، على الرغم من أنني أجد متداخلة comprehensions بشكل هامشي فقط للقراءة

الأكثر وضوحا (وأنا أزعم أكثر قابلية للقراءة) الجواب هو عدم استخدام قائمة الفهم أو مولد التعبير ، بل حقيقية مولد:

def gen_expensive(mylist):
    for item in mylist:
        result = expensive(item)
        if result:
            yield result

فإنه يأخذ المزيد من المساحة الأفقية, لكنه أسهل بكثير لنرى ماذا يفعل في لمحة ، وكنت في نهاية المطاف عدم تكرار نفسك.

result = [x for x in map(expensive,mylist) if x]

خريطة() سيعود قائمة قيم كل كائن في قائمتي مرت باهظة الثمن().ثم يمكنك قائمة-فهم أن تجاهل القيم التي لا داعي لها.

هذا هو إلى حد ما مثل متداخلة الفهم ، ولكن ينبغي أن يكون أسرع (منذ مترجم بايثون يمكن تحسين ذلك بسهولة إلى حد ما).

هذا هو بالضبط ما مولدات مناسبة للتعامل مع:

result = (expensive(x) for x in mylist)
result = (do_something(x) for x in result if some_condition(x))
...
result = [x for x in result if x]  # finally, a list
  1. هذا يجعل من الواضح تماما ما يحدث خلال كل مرحلة من مراحل خط أنابيب.
  2. صريح على ضمنيا
  3. يستخدم المولدات في كل مكان حتى الخطوة الأخيرة, لذلك لا كبيرة المتوسطة قوائم

cf: 'مولد الحيل نظام المبرمجين' ديفيد بيزلي

يمكنك دائما memoize على expensive() وظيفة بحيث واصفا إياه في المرة الثانية هو مجرد بحث عن احتساب قيمة x.

هنا هي مجرد واحدة من العديد من تطبيقات memoize كما الديكور.

هل يمكن أن memoize تكلفة(x) (و إذا كنت تتصل تكلفة(x) في كثير من الأحيان ، ربما يجب أن memoize ذلك بأي شكل من الأشكال.هذه الصفحة يعطي تنفيذ memoize بايثون:

http://code.activestate.com/recipes/52201/

وهذا له فائدة إضافية مكلفة(x) يجوز تشغيل أقل من N مرات ، لأن أي إدخالات مكررة الاستفادة من مذكرة من السابق التنفيذ.

علما أن هذا يفترض تكلفة(x) هو الوظيفة الحقيقية, و لا تعتمد على الدولة الخارجية التي قد تتغير.إذا مكلفة(x) لا تعتمد على الدولة الخارجية ، يمكنك الكشف عن عندما تتغير حالة أو أنت تعرف ذلك متعود تغيير خلال قائمة على الفهم, ثم يمكنك إعادة تعيين المذكرات قبل الفهم.

سوف يكون تفضيل:

itertools.ifilter(bool, (expensive(x) for x in mylist))

هذا له ميزة:

هناك سهل القديمة استخدام for حلقة إلحاق لائحة أيضا:

result = []
for x in mylist:
    expense = expensive(x)
    if expense:
        result.append(expense)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top