كيفية إزالة العناصر من القائمة في حين بالتكرار?

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

  •  05-07-2019
  •  | 
  •  

سؤال

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

for tup in somelist:
    if determine(tup):
         code_to_remove_tup

ما ينبغي أن تستخدم في مكان code_to_remove_tup?أنا لا يمكن معرفة كيفية إزالة هذا البند في هذه الموضة.

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

المحلول

ويمكنك استخدام الفهم قائمة لإنشاء قائمة جديدة تحتوي فقط العناصر التي لا تريد إزالة:

somelist = [x for x in somelist if not determine(x)]

وأو عن طريق تعيين لsomelist[:] شريحة، يمكنك يتحور القائمة الموجودة لاحتواء فقط العناصر التي تريد:

somelist[:] = [x for x in somelist if not determine(x)]

وهذا النهج يمكن أن تكون مفيدة إذا كانت هناك إشارات أخرى إلى somelist أن الحاجة لتعكس التغييرات.

وبدلا من الفهم، يمكن أيضا استخدام itertools. في بايثون 2:

from itertools import ifilterfalse
somelist[:] = ifilterfalse(determine, somelist)

وأو في بيثون 3:

from itertools import filterfalse
somelist[:] = filterfalse(determine, somelist)

نصائح أخرى

الإجابات مما يشير إلى قائمة comprehensions تقريبا الصحيح -- إلا أنها بناء جديدة تماما من القائمة ثم تعطيه نفس اسم القائمة القديمة كما أنها لا تعديل لائحة قديمة في المكان.وهذا يختلف عن ما كنت تفعله قبل إزالة انتقائية ، كما في @لينارت اقتراح إنها أسرع ، ولكن إذا كانت القائمة الخاصة بك الوصول إليها عبر إشارات متعددة حقيقة أن كنت مجرد reseating أحد المراجع وليس تغيير قائمة هدف في حد ذاته يمكن أن يؤدي إلى دهاء ، الكارثية البق.

لحسن الحظ, فإنه من السهل للغاية للحصول على كل من سرعة قائمة comprehensions المطلوبة دلالات في المكان تغيير فقط كود:

somelist[:] = [tup for tup in somelist if determine(tup)]

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

وتحتاج إلى أن تأخذ نسخة من القائمة وتكرار عبر لأول مرة، أو ستفشل التكرار مع ما يمكن أن يكون نتائج غير متوقعة.

وعلى سبيل المثال (يعتمد على نوع من القائمة):

for tup in somelist[:]:
    etc....

وعلى سبيل المثال:

>>> somelist = range(10)
>>> for x in somelist:
...     somelist.remove(x)
>>> somelist
[1, 3, 5, 7, 9]

>>> somelist = range(10)
>>> for x in somelist[:]:
...     somelist.remove(x)
>>> somelist
[]
for i in range(len(somelist) - 1, -1, -1):
    if some_condition(somelist, i):
        del somelist[i]

وكنت بحاجة للذهاب الى الوراء وإلا فإنه أشبه نشر قبالة فرع الشجرة التي كنت جالسا على: -)

وبايثون 2 المستخدمين: استبدال range التي كتبها xrange لتجنب إنشاء قائمة ضمنية

وأفضل نهج لديك لمثل هذا المثال سيكون href="http://docs.python.org/tutorial/datastructures.html#list-comprehensions" قائمة الفهم

somelist = [tup for tup in somelist if determine(tup)]

في الحالات التي كنت تفعل شيئا أكثر تعقيدا من استدعاء دالة determine، انا افضل إنشاء قائمة جديدة وببساطة إلحاق إلى أنها ذهبت. على سبيل المثال

newlist = []
for tup in somelist:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)
somelist = newlist

ونسخ القائمة باستخدام remove قد جعل الرمز الخاص بك تبدو قليلا أكثر نظافة، كما هو موضح في واحدة من الإجابات أدناه. يجب عليك بالتأكيد لن تفعل هذا لقوائم كبيرة للغاية، لأن هذا ينطوي على أول نسخ قائمة كاملة، وأداء أيضا عملية O(n) remove لكل عنصر يتم إزالتها، مما يجعل هذه الخوارزمية على O(n^2).

for tup in somelist[:]:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)

الرسمية بيثون 2 تعليمي 4.2."البيانات"

https://docs.python.org/2/tutorial/controlflow.html#for-statements

هذا الجزء من مستندات يجعل من الواضح أن:

  • تحتاج إلى إجراء نسخة من يتحرك من قائمة تعديل
  • طريقة واحدة للقيام بذلك هي مع شريحة التدوين [:]

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

>>> words = ['cat', 'window', 'defenestrate']
>>> for w in words[:]:  # Loop over a slice copy of the entire list.
...     if len(w) > 6:
...         words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']

بيثون 2 الوثائق 7.3."لبيان"

https://docs.python.org/2/reference/compound_stmts.html#for

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

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

for x in a[:]:
    if x < 0: a.remove(x)

إلا أنني أختلف مع هذا التنفيذ منذ .remove() وقد أعاد القائمة بأكملها لإيجاد قيمة.

بدلا من ذلك, إما:

  • تبدأ مجموعة جديدة من الصفر ، .append() تعود في النهاية: https://stackoverflow.com/a/1207460/895245

    هذه المرة كفاءة ، ولكن مساحة أقل كفاءة لأنها تحافظ نسخة من المصفوفة حولها خلال التكرار.

  • استخدام del مع فهرس: https://stackoverflow.com/a/1207485/895245

    هذا هو الأكثر فعالية من حيث المساحة حيث أنه يوزع مجموعة نسخ وإنما هو وقت أقل كفاءة بسبب CPython قوائم يتم تنفيذها مع صفائف ديناميكية.

    وهذا يعني أن البند إزالة يتطلب تحويل جميع البنود التالية مرة أخرى من جانب واحد الذي هو O(N).

عموما أنت فقط تريد أن تذهب أسرع .append() الخيار بشكل افتراضي ما لم يكن الذاكرة هو مصدر قلق كبير.

يمكن أن الثعبان هل هذا أفضل ؟

يبدو أن هذا الخصوص الثعبان API يمكن تحسينها.مقارنة مثلا مع نظيره جافا ListIterator, مما يجعل من الواضح تماما أنه لا يمكنك تعديل قائمة يجري يتحرك إلا مع التكرار نفسه ، ويعطيك كفاءة الطرق للقيام بذلك دون نسخ قائمة.

ولعل الأساس المنطقي هو أن الثعبان قوائم يفترض أن تكون ديناميكية مجموعة المدعومة ، وبالتالي فإن أي نوع من إزالة سوف يكون الوقت غير فعالة على أي حال ، في حين جافا أجمل واجهة الهرمي مع كل ArrayList و LinkedList تطبيقات ListIterator.

هناك لا يبدو أن يكون صريح قائمة مرتبطة نوع في بيثون stdlib إما: بيثون قائمة مرتبطة

وبالنسبة لأولئك الذين يحبون البرمجة الوظيفية:

somelist[:] = filter(lambda tup: not determine(tup), somelist)

أو

from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))

قد يكون من الذكاء أيضا مجرد إنشاء قائمة جديدة إذا كان عنصر القائمة الحالي يستوفي المعايير المطلوبة.

وهكذا:

for item in originalList:
   if (item != badValue):
        newList.append(item)

وولتجنب الاضطرار إلى إعادة رمز المشروع بأكمله مع اسم قوائم جديدة:

originalList[:] = newList

ملحوظة، من وثائق بيثون:

<اقتباس فقرة>   

وcopy.copy (خ)   العودة نسخة الضحلة من س.

     

وcopy.deepcopy (خ)   العودة نسخة عميق من س.

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

array = [lots of stuff]
arraySize = len(array)
i = 0
while i < arraySize:
    if someTest(array[i]):
        del array[i]
        arraySize -= 1
    else:
        i += 1

وما لا نعرفه هو مدى كفاءة تتم مقارنة اثنين من الحذف لنسخ قائمة كبيرة. يرجى التعليق إذا كان لديك أي فكرة.

وقد كتب

وهذه الإجابة أصلا ردا على السؤال الذي ومنذ ذلك الحين وضعت نسختين: إزالة الإحداثيات من القائمة على الثعبان

وهناك نوعان من المشاكل في التعليمات البرمجية:

1) عند استخدام إزالة ()، حاولت إزالة الأعداد الصحيحة في حين تحتاج إلى إزالة الصفوف (tuple).

2) للحلقة سيتم تخطي العناصر في القائمة.

ودعونا تشغيل من خلال ما يحدث عندما نقوم بتنفيذ التعليمات البرمجية:

>>> L1 = [(1,2), (5,6), (-1,-2), (1,-2)]
>>> for (a,b) in L1:
...   if a < 0 or b < 0:
...     L1.remove(a,b)
... 
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
TypeError: remove() takes exactly one argument (2 given)

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

>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>

وآها! كل عنصر من عناصر L1 هو في الواقع الصفوف (tuple). وهذا ما نحن بحاجة إلى أن يمر لإزالة (). الصفوف في بيثون من السهل جدا، انهم ببساطة التي تضم القيم بين قوسين. "أ، ب" ليست الصفوف (tuple)، ولكن "(أ، ب)" هو الصفوف (tuple). ولذا فإننا تعديل التعليمات البرمجية وتشغيله مرة أخرى:

# The remove line now includes an extra "()" to make a tuple out of "a,b"
L1.remove((a,b))

وهذا الرمز يعمل بدون أي خطأ، ولكن دعونا ننظر في قائمة ذلك النواتج:

L1 is now: [(1, 2), (5, 6), (1, -2)]

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

L1 = [(1,2),(5,6),(-1,-2),(1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
### Outputs:
L1 is now: [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

وكما يمكن أن نستنتج من هذه النتيجة، في كل مرة أن عبارة شرطية بتقييم إلى true وعنصر قائمة وإزالتها، والتكرار التالي من الحلقة سيتم تخطي تقييم العنصر التالي في القائمة لقيمها وتقع الآن في مؤشرات مختلفة.

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

L2 = L1
for (a,b) in L1:
    if a < 0 or b < 0 :
        L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
print L2 is L1
del L1
L1 = L2; del L2
print ("L1 is now: ", L1)

ومع ذلك، فإن الناتج سيكون مطابقا لمن قبل:

'L1 is now: ', [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

وهذا هو لأنه عندما أنشأنا L2، الثعبان لم يكن في الواقع خلق كائن جديد. بدلا من ذلك، مجرد الإشارة L2 لنفس موضوع L1. يمكننا التحقق من ذلك مع 'هو' الذي يختلف عن مجرد "يساوي" (==).

>>> L2=L1
>>> L1 is L2
True

ونحن يمكن أن تجعل نسخة باستخدام صحيح على copy.copy (). ثم كل شيء يعمل كما هو متوقع:

import copy
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
L2 = copy.copy(L1)
for (a,b) in L1:
    if a < 0 or b < 0 :
        L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
del L1
L1 = L2; del L2
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]

وأخيرا، هناك حل واحد أنظف من الحاجة إلى تقديم نسخة جديدة تماما من L1. وظيفة عكس ():

L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
for (a,b) in reversed(L1):
    if a < 0 or b < 0 :
        L1.remove((a,b))
print ("L1 is now: ", L1)
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]

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

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

inlist = [{'field1':10, 'field2':20}, {'field1':30, 'field2':15}]    
for idx, i in enumerate(inlist):
    do some stuff with i['field1']
    if somecondition:
        xlist.append(idx)
for i in reversed(xlist): del inlist[i]

وenumerate يتيح لك الوصول إلى هذا البند، ومؤشر في آن واحد. reversed ذلك هو أن المؤشرات التي كنت تريد الذهاب لحذف في وقت لاحق لا تتغير عليك.

وقد ترغب في استخدام filter() متوفرة كما في المدمج.

لمزيد من التفاصيل تحقق هنا

يمكنك محاولة ل-حلقات في الاتجاه المعاكس حتى some_list عليك أن تفعل شيئا مثل:

list_len = len(some_list)
for i in range(list_len):
    reverse_i = list_len - 1 - i
    cur = some_list[reverse_i]

    # some logic with cur element

    if some_condition:
        some_list.pop(reverse_i)

هذا الطريق هو مؤشر الانحياز و لا تعاني من قائمة التحديثات (بغض النظر ما إذا كنت البوب لئيم العنصر أو لا).

وأحد الحلول الممكنة، ومفيدة إذا كنت تريد تقم بإزالة بعض الأشياء فقط، ولكن أيضا أن تفعل شيئا مع جميع العناصر في حلقة واحدة:

alist = ['good', 'bad', 'good', 'bad', 'good']
i = 0
for x in alist[:]:
    if x == 'bad':
        alist.pop(i)
        i -= 1
    # do something cool with x or just print x
    print(x)
    i += 1

ومعظم الإجابات هنا أريدك أن إنشاء نسخة من القائمة. كان لي حالة استخدام حيث كانت قائمة طويلة جدا (110K البنود) وكان أكثر ذكاء للحفاظ على الحد من القائمة بدلا من ذلك.

وأولا وقبل كل ستحتاج إلى استبدال حلقة foreach مع حلقة في حين و

i = 0
while i < len(somelist):
    if determine(somelist[i]):
         del somelist[i]
    else:
        i += 1

لا تتغير قيمة i في إذا كتلة لأنك سوف ترغب في الحصول على قيمة العنصر الجديد من المؤشر نفسه، مرة واحدة يتم حذف العنصر القديم.

وكنت بحاجة إلى القيام بشيء مماثل وفي حالتي كانت المشكلة الذاكرة - أنا في حاجة لدمج عدة كائنات بيانات ضمن القائمة، بعد القيام ببعض الاشياء معهم، كما وجوه جديدة، وتحتاج إلى التخلص من كل دخول I تم دمج لتجنب تكرار كل منهم وتفجير الذاكرة. في حالتي وجود الكائنات في القاموس بدلا من قائمة عملت غرامة:

و`` `

k = range(5)
v = ['a','b','c','d','e']
d = {key:val for key,val in zip(k, v)}

print d
for i in range(5):
    print d[i]
    d.pop(i)
print d

و`` `

TLDR:

كتبت المكتبة التي تسمح لك أن تفعل هذا:

from fluidIter import FluidIterable
fSomeList = FluidIterable(someList)  
for tup in fSomeList:
    if determine(tup):
        # remove 'tup' without "breaking" the iteration
        fSomeList.remove(tup)
        # tup has also been removed from 'someList'
        # as well as 'fSomeList'

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

يجب أن تعمل على كل قابلة للتغيير تسلسل ليس فقط القوائم.


الإجابة الكاملة:

تحرير:آخر المثال التعليمات البرمجية في هذا الجواب يعطي استخدام القضية لماذا قد تريد في بعض الأحيان إلى تعديل قائمة في المكان بدلا من استخدام قائمة الفهم.الجزء الأول من الأجوبة بمثابة البرنامج التعليمي من كيف مجموعة يمكن تعديلها في المكان.

الحل يلي على من هذا الجواب (عن ذات السؤال) من senderle.وهو ما يفسر كيف أن مؤشر مجموعة يتم تحديث حين بالتكرار من خلال القائمة التي تم تعديلها.الحل أدناه مصممة بشكل صحيح مسار مؤشر مجموعة حتى إذا كانت القائمة المعدلة.

تحميل fluidIter.py من هنا https://github.com/alanbacon/FluidIterator, هو فقط ملف واحد حتى لا تحتاج إلى تثبيت بوابة.لا يوجد المثبت لذلك سوف تحتاج إلى تأكد من أن الملف هو في بيثون مسار الذاتية الخاصة بك.تم كتابة رمز لبيثون 3 و هو لم تختبر على بيثون 2.

from fluidIter import FluidIterable
l = [0,1,2,3,4,5,6,7,8]  
fluidL = FluidIterable(l)                       
for i in fluidL:
    print('initial state of list on this iteration: ' + str(fluidL)) 
    print('current iteration value: ' + str(i))
    print('popped value: ' + str(fluidL.pop(2)))
    print(' ')

print('Final List Value: ' + str(l))

هذا وسوف تنتج الإخراج التالي:

initial state of list on this iteration: [0, 1, 2, 3, 4, 5, 6, 7, 8]
current iteration value: 0
popped value: 2

initial state of list on this iteration: [0, 1, 3, 4, 5, 6, 7, 8]
current iteration value: 1
popped value: 3

initial state of list on this iteration: [0, 1, 4, 5, 6, 7, 8]
current iteration value: 4
popped value: 4

initial state of list on this iteration: [0, 1, 5, 6, 7, 8]
current iteration value: 5
popped value: 5

initial state of list on this iteration: [0, 1, 6, 7, 8]
current iteration value: 6
popped value: 6

initial state of list on this iteration: [0, 1, 7, 8]
current iteration value: 7
popped value: 7

initial state of list on this iteration: [0, 1, 8]
current iteration value: 8
popped value: 8

Final List Value: [0, 1]

أعلاه استخدمنا pop الطريقة على السائل قائمة الكائن.الشائعة الأخرى iterable الأساليب هي أيضا تنفيذ مثل del fluidL[i], .remove, .insert, .append, .extend.القائمة كما يمكن تعديلها باستخدام شرائح (sort و reverse أساليب لا تنفذ).

الشرط الوحيد هو أنه يجب عليك فقط تعديل قائمة في المكان, إذا في أي نقطة fluidL أو l نقلوا إلى قائمة مختلفة كائن الكود لن يعمل.الأصلي fluidL كائن لا يزال يستخدم من قبل للحلقة ولكن أن تصبح خارج نطاق الولايات المتحدة إلى تعديل.

أي

fluidL[2] = 'a'   # is OK
fluidL = [0, 1, 'a', 3, 4, 5, 6, 7, 8]  # is not OK

إذا كنا نريد الوصول إلى القيمة الحالية للمؤشر قائمة لا يمكننا استخدام تعداد ، هذا فقط بحساب عدد المرات لحلقة تشغيل.بدلا من ذلك سوف نستخدم التكرار الكائن مباشرة.

fluidArr = FluidIterable([0,1,2,3])
# get iterator first so can query the current index
fluidArrIter = fluidArr.__iter__()
for i, v in enumerate(fluidArrIter):
    print('enum: ', i)
    print('current val: ', v)
    print('current ind: ', fluidArrIter.currentIndex)
    print(fluidArr)
    fluidArr.insert(0,'a')
    print(' ')

print('Final List Value: ' + str(fluidArr))

وهذا الإخراج التالية:

enum:  0
current val:  0
current ind:  0
[0, 1, 2, 3]

enum:  1
current val:  1
current ind:  2
['a', 0, 1, 2, 3]

enum:  2
current val:  2
current ind:  4
['a', 'a', 0, 1, 2, 3]

enum:  3
current val:  3
current ind:  6
['a', 'a', 'a', 0, 1, 2, 3]

Final List Value: ['a', 'a', 'a', 'a', 0, 1, 2, 3]

على FluidIterable الدرجة فقط يوفر المجمع الأصلي قائمة الكائن.الكائن الأصلي يمكن الوصول إليها كخاصية من السوائل كائن مثل ذلك:

originalList = fluidArr.fixedIterable

المزيد من الأمثلة / الاختبارات يمكن العثور عليها في if __name__ is "__main__": في الجزء السفلي من fluidIter.py.هذه هي يستحق النظر لأنها تفسر ما يحدث في مختلف الحالات.مثل:استبدال أجزاء كبيرة من القائمة باستخدام شريحة.أو باستخدام (وتعديل) نفس iterable في المتداخلة عن الحلقات.

كما ذكرت أن تبدأ مع:هذا هو الحل معقد من شأنها أن تؤذي قراءة التعليمات البرمجية الخاصة بك وجعلها أكثر صعوبة التصحيح.ولذلك حلول أخرى مثل قائمة comprehensions المذكورة في ديفيد Raznick هو الجواب ينبغي النظر أولا.أن يقال, لقد وجدت مرات حيث هذه الفئة كانت مفيدة لي و قد تم استخدامها أسهل من تتبع مؤشرات العناصر التي تحتاج إلى حذف.


تحرير:كما ذكر في التعليقات هذا الجواب لا حقا الحاضر مشكلة هذا النهج يوفر حلا.سوف نحاول معالجة هذا هنا:

قائمة comprehensions توفر وسيلة لإنشاء قائمة جديدة ولكن هذه النهج يميلون إلى النظر إلى كل عنصر في العزلة بدلا من الوضع الحالي من القائمة ككل.

أي

newList = [i for i in oldList if testFunc(i)]

ولكن ما إذا كانت نتيجة testFunc يعتمد على العناصر التي تمت إضافتها إلى newList بالفعل ؟ أو العناصر التي لا تزال في oldList التي يمكن أن تضاف في المرة القادمة ؟ قد يكون هناك طريقة لاستخدام قائمة على الفهم ولكن سوف تبدأ في فقدان انها الأناقة و بالنسبة لي فإنه يبدو أسهل لتعديل قائمة في المكان.

رمز أدناه هو مثال واحد من خوارزمية التي تعاني من المشكلة المذكورة أعلاه.الخوارزمية سوف تقلل من قائمة بحيث لا عنصر متعددة من أي عنصر آخر.

randInts = [70, 20, 61, 80, 54, 18, 7, 18, 55, 9]
fRandInts = FluidIterable(randInts)
fRandIntsIter = fRandInts.__iter__()
# for each value in the list (outer loop)
# test against every other value in the list (inner loop)
for i in fRandIntsIter:
    print(' ')
    print('outer val: ', i)
    innerIntsIter = fRandInts.__iter__()
    for j in innerIntsIter:
        innerIndex = innerIntsIter.currentIndex
        # skip the element that the outloop is currently on
        # because we don't want to test a value against itself
        if not innerIndex == fRandIntsIter.currentIndex:
            # if the test element, j, is a multiple 
            # of the reference element, i, then remove 'j'
            if j%i == 0:
                print('remove val: ', j)
                # remove element in place, without breaking the
                # iteration of either loop
                del fRandInts[innerIndex]
            # end if multiple, then remove
        # end if not the same value as outer loop
    # end inner loop
# end outerloop

print('')
print('final list: ', randInts)

الإخراج النهائي تخفيض القائمة أدناه

outer val:  70

outer val:  20
remove val:  80

outer val:  61

outer val:  54

outer val:  18
remove val:  54
remove val:  18

outer val:  7
remove val:  70

outer val:  55

outer val:  9
remove val:  18

final list:  [20, 61, 7, 55, 9]

والإجابات الأخرى الصحيحة التي عادة ما يكون فكرة سيئة لحذف من القائمة التي كنت بالتكرار. بالتكرار العكسي يتجنب المزالق، وإنما هو أكثر صعوبة لمتابعة التعليمات البرمجية التي يفعل ذلك، لذلك عادة كنت أفضل حالا باستخدام الفهم قائمة أو filter.

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

for i, item in enumerate(lst):
    if item % 4 == 0:
        foo(item)
        del lst[i]
        break

وهذا غالبا ما يكون أسهل للفهم من الفهم قائمة عندما كنت تفعل بعض العمليات مع آثار جانبية على العنصر الأول في القائمة التي تلبي بعض شرط ومن ثم إزالة هذا العنصر من القائمة بعد ذلك مباشرة.

الأسلوب الأكثر فعالية هو قائمة على الفهم ، كثير من الناس تظهر الحالة ، بالطبع ، هو أيضا وسيلة جيدة للحصول على iterator من خلال filter.

Filter يحصل على وظيفة و تسلسل. Filter ينطبق مرت وظيفة كل عنصر بدوره ، ومن ثم تقرر ما إذا كنت تريد الاحتفاظ أو تجاهل عنصر اعتمادا على ما إذا كانت الدالة قيمة الإرجاع هي True أو False.

هناك على سبيل المثال (على خلاف في tuple):

list(filter(lambda x:x%2==1, (1, 2, 4, 5, 6, 9, 10, 15)))  
# result: [1, 5, 9, 15]

تنبيه:يمكنك أيضا التعامل مع التكرار.التكرار في بعض الأحيان أفضل من متواليات.

أستطيع أن أفكر في ثلاثة نهج حل المشكلة الخاصة بك.وعلى سبيل المثال ، سوف إنشاء قائمة عشوائية من الصفوف somelist = [(1,2,3), (4,5,6), (3,6,6), (7,8,9), (15,0,0), (10,11,12)].شرط أن لا يختار هو sum of elements of a tuple = 15.في القائمة النهائية سيكون لدينا فقط تلك الصفوف المبلغ الذي لا يساوي 15.

ما اخترته هو اختيارها عشوائيا سبيل المثال. لا تتردد في تغيير على قائمة الصفوف و الشرط التي اخترتها.

الطريقة 1.> استخدام الإطار التي اقترحتموها (حيث يملأ في مدونة داخل حلقة for).يمكنني استخدام رمز صغير مع del كيفية حذف المجموعة التي تلبي هذا الشرط.إلا أن هذا الأسلوب سوف يغيب tuple (الذي يرضي الشرط) إن اثنين على التوالي وضعت الصفوف تلبية بالنظر إلى الشرط.

for tup in somelist:
    if ( sum(tup)==15 ): 
        del somelist[somelist.index(tup)]

print somelist
>>> [(1, 2, 3), (3, 6, 6), (7, 8, 9), (10, 11, 12)]

الأسلوب 2.> إنشاء قائمة جديدة والتي تحتوي على عناصر (tuples) حيث تعطى حالة عدم الوفاء (هذا هو نفس الشيء مثل إزالة العناصر من القائمة حيث تعطى الشرط).ما يلي هو رمز لهذا:

newlist1 = [somelist[tup] for tup in range(len(somelist)) if(sum(somelist[tup])!=15)]

print newlist1
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]

الأسلوب 3.> العثور على المؤشرات حيث تعطى الشرط ، ومن ثم استخدام إزالة العناصر (tuples) الموافق تلك المؤشرات.ما يلي هو رمز لذلك.

indices = [i for i in range(len(somelist)) if(sum(somelist[i])==15)]
newlist2 = [tup for j, tup in enumerate(somelist) if j not in indices]

print newlist2
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]

الأسلوب 1 و الطريقة 2 أسرع من الطريقة 3.Method2 و method3 أكثر كفاءة من method1.أنا تفضل method2.المذكورة أعلاه على سبيل المثال ، time(method1) : time(method2) : time(method3) = 1 : 1 : 1.7

حلقة سوف يكون من خلال تكرار مؤشر..

النظر لديك قائمة ،

[5, 7, 13, 29, 65, 91]

لديك باستخدام قائمة متغير يسمى lis.و باستخدام نفس لإزالة..

المتغير الخاص بك

lis = [5, 7, 13, 29, 35, 65, 91]
       0  1   2   3   4   5   6

خلال 5 التكرار ،

الخاص بك عدد 35 لم يكن رئيس الوزراء إذا كنت إزالته من القائمة.

lis.remove(y)

ثم القيمة التالية (65) ننتقل إلى المؤشر السابق.

lis = [5, 7, 13, 29, 65, 91]
       0  1   2   3   4   5

لذا 4 التكرار يتم مؤشر انتقلت إلى 5..

ولهذا حلقة الخاص بك لا تغطي 65 منذ انتقلت إلى المؤشر السابق.

لذلك يجب أن لا قائمة المراجع في آخر المتغير الذي لا يزال المرجع الأصلي بدلا من نسخ.

ite = lis #dont do it will reference instead copy

حتى لا نسخ من القائمة باستخدام list[::]

الآن سوف تعطي ،

[5, 7, 13, 29]

المشكلة هو إزالة قيمة من قائمة خلال التكرار ثم قائمة مؤشر الانهيار.

لذلك يمكنك محاولة الفهم بدلا من ذلك.

الذي يدعم جميع iterable مثل قائمة tuple ، ديكت ، سلسلة الخ

لأي شيء له القدرة على أن تكون كبيرة حقا، وأنا استخدم ما يلي:

import numpy as np

orig_list = np.array([1, 2, 3, 4, 5, 100, 8, 13])

remove_me = [100, 1]

cleaned = np.delete(orig_list, remove_me)
print(cleaned)

وينبغي أن يكون أسرع بكثير من أي شيء آخر.

في بعض الحالات، حيث كنت تفعل أكثر من مجرد تصفية قائمة عنصر واحد في وقت و، وتريد تكرار لتغيير بينما بالتكرار.

وهنا مثال حيث نسخ القائمة مسبقا غير صحيح، عكس التكرار من المستحيل وقائمة على الفهم هو أيضا ليس خيارا.

""" Sieve of Eratosthenes """

def generate_primes(n):
    """ Generates all primes less than n. """
    primes = list(range(2,n))
    idx = 0
    while idx < len(primes):
        p = primes[idx]
        for multiple in range(p+p, n, p):
            try:
                primes.remove(multiple)
            except ValueError:
                pass #EAFP
        idx += 1
        yield p

إذا كنت ستستخدم القائمة الجديدة في وقت لاحق، يمكنك ببساطة وضع إيليم إلى بلا، ومن ثم الحكم عليها في حلقة لاحقة، مثل هذا

for i in li:
    i = None

for elem in li:
    if elem is None:
        continue

في هذه الطريقة، يمكنك dont't تحتاج نسخ قائمة وانه من الاسهل لفهم.

وuppose قائمة رقم وتريد لإزالة كافة لا تقبل القسمة التي كتبها 3،

list_number =[i for i in range(100)]

وباستخدام list comprehension، وهذا سوف careate قائمة جديدة وخلق مساحة الذاكرة جديد

new_list =[i for i in list_number if i%3!=0]

وباستخدام وظيفة lambda filter، وهذا سيخلق القائمة الجديدة الناتجة وتستهلك مساحة memeory

new_list = list(filter(lambda x:x%3!=0, list_number))

ودون استهلاك مساحة الذاكرة لقائمة جديدة وتعديل قائمة موجودة

for index, value in enumerate(list_number):
    if list_number[index]%3==0:
        list_number.remove(value)

وعلى الفور كنت ترغب في إنشاء نسخة من قائمة حتى تتمكن من أن كمرجع عند بالتكرار عبر وحذف الصفوف في تلك القائمة التي تلبي معايير معينة.

وبعد ذلك يعتمد على نوع القائمة التي تريدها للانتاج سواء كان ذلك قائمة من الصفوف التي تم حذفها أو قائمة من الصفوف التي لم يتم إزالتها.

وكما أشار ديفيد، وأنا أوصي الفهم القائمة للحفاظ على العناصر التي لا تريد إزالته.

somelist = [x for x in somelist if not determine(x)]
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top