পাইথনে দুটি জেনারেটরে কীভাবে যোগদান করবেন?


187

আমি নিম্নলিখিত কোডটি পরিবর্তন করতে চাই

for directory, dirs, files in os.walk(directory_1):
    do_something()

for directory, dirs, files in os.walk(directory_2):
    do_something()

এই কোড:

for directory, dirs, files in os.walk(directory_1) + os.walk(directory_2):
    do_something()

আমি ত্রুটি পেয়েছি:

+: 'জেনারেটর' এবং 'জেনারেটর' এর জন্য অসমর্থিত অপরেন্দ্র প্রকার (গুলি)

পাইথনে দুটি জেনারেটরে কীভাবে যোগদান করবেন?


1
আমি পাইথনকেও এভাবে কাজ করতে চাই। ঠিক একই ত্রুটি পেয়েছি!
অ্যাডাম কুরকিউইচ

উত্তর:


232

আমার মনে হয় itertools.chain()এটা করা উচিত।


5
একটি মনে রাখা উচিত যে এর ফেরতের মান itertools.chain()একটি types.GeneratorTypeউদাহরণ দেয় না return ঠিক সঠিক ক্ষেত্রে গুরুত্বপূর্ণ যদি।
রিগা

1
আপনিও কেন একটি কাজের উদাহরণ লিখে রাখেন না?
চার্লি পার্কার

74

কোডের একটি উদাহরণ:

from itertools import chain

def generator1():
    for item in 'abcdef':
        yield item

def generator2():
    for item in '123456':
        yield item

generator3 = chain(generator1(), generator2())
for item in generator3:
    print item

10
ইতিমধ্যে বিদ্যমান, উচ্চ উত্সাহিত itertools.chain()উত্তরের সাথে এই উদাহরণটি যুক্ত করবেন না কেন ?
জিন-ফ্রান্সোইস কর্পেট

51

পাইথনে (3.5 বা তার বেশি) আপনি এটি করতে পারেন:

def concat(a, b):
    yield from a
    yield from b

7
এত অজগর।
রমজান পোলাট

9
আরও সাধারণ: def chain(*iterables): for iterable in iterables: yield from iterable(রাখুন defএবং for। পৃথক লাইন যখন আপনি এটি চালানো)
wjandrea

সবকিছু থেকে একটি আগে থেকে কিছু পাওয়া পাওয়া যাচ্ছে না অথবা তারা alternated হচ্ছে?
সমস্যাসমূহ

নিবন্ধন করুন aযতক্ষণ bনা এটি পুনরুক্তিকারী না হয় কেবল সমস্ত কিছু এখান থেকে প্রাপ্ত না হওয়া পর্যন্ত কেবল তা পরীক্ষা করা হয় । TypeErrorজন্য bহচ্ছে না কোনো ইটারেটরে পরে আসতে হবে।
গি ট্রান্সসিত

35

সাধারণ উদাহরণ:

from itertools import chain
x = iter([1,2,3])      #Create Generator Object (listiterator)
y = iter([3,4,5])      #another one
result = chain(x, y)   #Chained x and y

3
ইতিমধ্যে বিদ্যমান, উচ্চ উত্সাহিত itertools.chain()উত্তরের সাথে এই উদাহরণটি যুক্ত করবেন না কেন ?
জিন-ফ্রান্সোইস কর্পেট

এটি একেবারেই সঠিক নয়, যেহেতু itertools.chainএকটি জেনারেটর নয়, একটি পুনরুক্তিকারীর ফেরত দেয়।
ডেভিড জে

তুমি কি করতে পার না chain([1, 2, 3], [3, 4, 5])?
করমান

10

Itertools.chain.from_iterable এর মাধ্যমে আপনি যেমন কাজ করতে পারেন:

def genny(start):
  for x in range(start, start+3):
    yield x

y = [1, 2]
ab = [o for o in itertools.chain.from_iterable(genny(x) for x in y)]
print(ab)

আপনি একটি অপ্রয়োজনীয় তালিকা বোঝার ব্যবহার করছেন using gennyএটি ইতিমধ্যে যখন কোনও জেনারেটর ফিরিয়ে দেয় তখন আপনি একটি অপ্রয়োজনীয় জেনারেটর এক্সপ্রেশনও ব্যবহার করছেন । list(itertools.chain.from_iterable(genny(x)))আরও অনেক সংক্ষিপ্ত।
Corman 20

প্রশ্ন অনুসারে দুটি জেনারেটর তৈরি করার সহজ উপায় ছিল IST বোধগম্যতা। আমার উত্তরটি সে ক্ষেত্রে কিছুটা বিশৃঙ্খলাবদ্ধ।
অ্যান্ড্রু পেট

আমি মনে করি যে বিদ্যমান উত্তরগুলিতে এই উত্তরটি যুক্ত করার কারণটি ছিল তাদের মোকাবেলায় প্রচুর জেনারেটর থাকার ক্ষেত্রে সহায়তা করা।
অ্যান্ড্রু পেট

এটি একটি সহজ উপায় নয়, অনেক সহজ উপায় আছে। বিদ্যমান জেনারেটরে জেনারেটর এক্সপ্রেশন ব্যবহার করা কার্যকারিতা কমিয়ে দেবে, এবং listনির্মাতা তালিকার বোধগম্যতার চেয়ে অনেক বেশি পঠনযোগ্য। এই পদ্ধতিতে আপনার পদ্ধতিটি অনেক বেশি অপঠনযোগ্য।
Corman

করম্যান, আমি সম্মত হই যে আপনার তালিকার নির্মাতা সত্যই আরও পাঠযোগ্য আপনার 'অনেকগুলি সহজ উপায়' দেখতে ভালই লাগবে যদিও ... আমি মনে করি উপরের ওজান্দ্রিয়ার মন্তব্যটি itertools.chain.from_iteable হিসাবে একই রকম আচরণ করবে বলে মনে হয় তাদের প্রতিযোগিতা করা এবং দ্রুততম কোনটি দেখা ভাল।
অ্যান্ড্রু পেট

8

এখানে এটি নেস্টেড এস সহ একটি জেনারেটর এক্সপ্রেশন ব্যবহার করছে for:

a = range(3)
b = range(5)
ab = (i for it in (a, b) for i in it)
assert list(ab) == [0, 1, 2, 0, 1, 2, 3, 4]

2
একটু ব্যাখ্যা করলে ক্ষতি হবে না।
রমজান পোলাট

ঠিক আছে, আমি পাইথনের ডকুমেন্টেশনের চেয়ে ভাল এটি ব্যাখ্যা করতে পারি বলে আমি মনে করি না।
আলেক্সি

(জেনারেটরের এক্সপ্রেশন ডকুমেন্টেশন আমার উত্তর থেকে লিঙ্ক করা হয়েছে আমি আমার উত্তর মধ্যে কপি এবং ডকুমেন্টেশন পেস্ট করতে একটি ভাল কারণ দেখতে না।।)
আলেক্সি

3

একজন আনপ্যাক অপারেটরও ব্যবহার করতে পারেন *:

concat = (*gen1(), *gen2())

দ্রষ্টব্য: 'অলস' পুনরাবৃত্তদের জন্য সবচেয়ে দক্ষতার সাথে কাজ করে। বিভিন্ন ধরণের বোধগম্যতার সাথেও ব্যবহার করা যেতে পারে। জেনারেটর কনক্টের জন্য পছন্দের উপায়টি @ ইউডুসের উত্তর থেকে


1

আপনি যদি জেনারেটরগুলি পৃথক রাখতে চান তবে একই সাথে পুনরায় পুনরায় পুনরুক্তি করতে পারেন তবে আপনি জিপ () ব্যবহার করতে পারেন:

দ্রষ্টব্য: দুটি জেনারেটরের সংক্ষিপ্ত স্থানে ইস্ট্রেশন বন্ধ হয়

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

for (root1, dir1, files1), (root2, dir2, files2) in zip(os.walk(path1), os.walk(path2)):

    for file in files1:
        #do something with first list of files

    for file in files2:
        #do something with second list of files

0

বলুন যে আমাদের জেনারেটর করতে হবে (জেন 1 এবং জেন 2) এবং আমরা কিছু অতিরিক্ত গণনা করতে চাই যার জন্য উভয়ের ফলাফল প্রয়োজন। আমরা মানচিত্রের পদ্ধতির মাধ্যমে এই জাতীয় ফাংশন / গণনার ফলাফলটি ফিরিয়ে দিতে পারি, যার ফলস্বরূপ এমন কোনও জেনারেটর প্রদান করে যা আমরা লুপ করতে পারি।

এই পরিস্থিতিতে, ল্যাম্বদা ফাংশনটির মাধ্যমে ফাংশন / গণনাটি প্রয়োগ করা দরকার। জটিল অংশটি হ'ল মানচিত্রের অভ্যন্তরে এবং এর ল্যাম্বদা ফাংশনটি আমরা কী করতে চাই।

প্রস্তাবিত সমাধানের সাধারণ ফর্ম:

def function(gen1,gen2):
        for item in map(lambda x, y: do_somethin(x,y), gen1, gen2):
            yield item

0

এই সমস্ত জটিল সমাধান ...

শুধু কর:

for dir in director_1, directory_2:
    for directory, dirs, files in os.walk(dir):
        do_something()

আপনি যদি সত্যই উভয় জেনারেটরকে "যোগদান" করতে চান তবে করুন:

for directory, dirs, files in 
        [x for osw in [os.walk(director_1), os.walk(director_2)] 
               for x in osw]:
    do_something()
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.