python - العثور على جميع الأرقام في ملف واحد ليست في ملف آخر في بيثون




arrays file (3)

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

في البداية ، يمكنك القيام بذلك لإنشاء بعض ملفات الاختبار:

seq 0 3 100 > 3k.txt
seq 0 2 100 > 2k.txt

ثم تقوم بتشغيل هذا الكود:

i1 = iter(open("3k.txt"))
i2 = iter(open("2k.txt"))
a = int(next(i1))
b = int(next(i2))
aNotB = []
# bNotA = []
while True:
    try:
        if a < b:
            aNotB += [a]
            a = int(next(i1, None))
        elif a > b:
            # bNotA += [a]
            b = int(next(i2, None))
        elif a == b:
            a = int(next(i1, None))
            b = int(next(i2, None))
    except TypeError:
        if not b:
            aNotB += list(i1)
            break
        else:
            # bNotA += list(i1)
            break
print(res)

انتاج:

[3 ، 9 ، 15 ، 21 ، 27 ، 33 ، 39 ، 45 ، 51 ، 57 ، 63 ، 69 ، 75 ، 81 ، 87 ، 93 ، 99] إذا كنت تريد كل من نتيجة aNotB و bNotA ، يمكنك إلغاء هذين خطوط.

مقارنة التوقيت مع إجابة Andrej Kesely:

$ seq 0 3 1000000 > 3k.txt
$ seq 0 2 1000000 > 2k.txt
$ time python manual_iter.py        
python manual_iter.py  0.38s user 0.00s system 99% cpu 0.387 total
$ time python heapq_groupby.py        
python heapq_groupby.py  1.11s user 0.00s system 99% cpu 1.116 total

يوجد ملفان ، FileA و FileB ، ونحتاج إلى إيجاد جميع الأرقام الموجودة في FileA والتي ليست موجودة في FileB. يتم فرز جميع الأرقام الموجودة في FileA ويتم فرز جميع الأرقام الموجودة في FileB. فمثلا،

إدخال:

FileA = [1, 2, 3, 4, 5, ...]
FileB = [1, 3, 4, 6, ...]

انتاج:

[2, 5, ...]

الذاكرة محدودة للغاية ولا يمكن حتى تحميل ملف كامل في الذاكرة في وقت واحد. أيضا الخطي أو أقل تعقيد الوقت هو مطلوب.

لذلك إذا كانت الملفات صغيرة بما يكفي لتناسبها في الذاكرة ، فيمكننا تحميلها وتهيئة محتوياتها كمجموعتين ، ثم نحدث اختلافًا محددًا بحيث يتم حل المشكلة في O (1) أو التعقيد الزمني الثابت.

set(contentsofFileA)-set(contentsofFileB)

ولكن نظرًا لأن الملفات كبيرة جدًا ، فلن تتمكن من تحميلها بالكامل في الذاكرة وبالتالي فإن هذا غير ممكن.

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

يجب حل المشكلة في تعقيد الوقت الخطي أو الأقل وبدون تحميل الملفات بالكامل في الذاكرة. أي مساعدة؟


حل بسيط يعتمد على قراءة الملف (على افتراض أن كل سطر يحمل رقمًا):

results = []
with open('file1.csv') as file1, open('file2.csv') as file2:
        var1 = file1.readline()
        var2 = file2.readline()
        while var1:
            while var1 and var2:
                if int(var1) < int(var2):
                    results.append(int(var1))
                    var1 = file1.readline()
                elif int(var1) > int(var2):
                    var2 = file2.readline()
                elif int(var1) == int(var2):
                    var1 = file1.readline()
                    var2 = file2.readline()
            if var1:
                results.append(int(var1))
                var1 = file1.readline()
print(results)
output = [2, 5, 7, 9]

يمكنك الجمع بين itertools.groupby ( doc ) و heapq.merge ( doc ) للتكرار من خلال FileB و FileB بتكاسل (يعمل طالما يتم فرز الملفات!)

FileA = [1, 1, 2, 3, 4, 5]
FileB = [1, 3, 4, 6]

from itertools import groupby
from heapq import merge

gen_a = ((v, 'FileA') for v in FileA)
gen_b = ((v, 'FileB') for v in FileB)

for v, g in groupby(merge(gen_a, gen_b, key=lambda k: int(k[0])), lambda k: int(k[0])):
    if any(v[1] == 'FileB' for v in g):
        continue
    print(v)

مطبوعات:

2
5

تحرير (القراءة من الملفات):

from itertools import groupby
from heapq import merge

gen_a = ((int(v.strip()), 1) for v in open('3k.txt'))
gen_b = ((int(v.strip()), 2) for v in open('2k.txt'))

for v, g in groupby(merge(gen_a, gen_b, key=lambda k: k[0]), lambda k: k[0]):
    if any(v[1] == 2 for v in g):
        continue
    print(v)

المعيار:

إنشاء ملفات ذات 10_000_000 عنصر:

seq 0 3 10000000 > 3k.txt
seq 0 2 10000000 > 2k.txt

يستغرق البرنامج النصي حوالي 10 ثوانٍ لإكماله:

real    0m10,656s
user    0m10,557s
sys 0m0,076s




out-of-memory