পাইথনগুলিতে পুনরাবৃত্তি করা যাবে?


129

আমি কি পাইথনে একটি পুনরুক্তি / জেনারেটর পুনরায় সেট করতে পারি? আমি ডিকট্রিডার ব্যবহার করছি এবং এটি ফাইলের শুরুতে পুনরায় সেট করতে চাই।


উত্তর:


84

আমি অনেকগুলি উত্তর দেখতে পাচ্ছি যা itertools.tee পরামর্শ দিচ্ছে , কিন্তু এটি ডক্সের জন্য একটি গুরুত্বপূর্ণ সতর্কতা উপেক্ষা করছে:

এই ইয়ারটোলের জন্য উল্লেখযোগ্য সহায়ক স্টোরেজ প্রয়োজন হতে পারে (অস্থায়ী ডেটা সংরক্ষণ করার জন্য কতটা প্রয়োজন তার উপর নির্ভর করে)। সাধারণভাবে, যদি কোনও পুনরুক্তিকারী অন্য পুনরুক্তি শুরু হওয়ার আগে যদি সবচেয়ে বেশি বা সমস্ত ডেটা ব্যবহার করে তবে list()তার পরিবর্তে এটি ব্যবহার করা আরও দ্রুত tee()

মূলত, teeসেই অবস্থা যেখানে দুটি (বা তার বেশি) এক পুনরুক্তিকারীর এর ক্লোনস, যখন একে অপরের সাথে "সিঙ্ক আউট", তাই না জন্য ডিজাইন করা হয়েছে অনেক দ্বারা বরং, তারা একই "সান্নিধ্যের" বলে (ক - একে অপরের পিছনে বা সামনে কয়েকটি আইটেম)। "শুরু থেকে আবার করুন" এর ওপির সমস্যার পক্ষে উপযুক্ত নয়।

L = list(DictReader(...))অন্যদিকে পুরোপুরি উপযুক্ত, যতক্ষণ না ডিক্টের তালিকা মেমরির মধ্যে স্বাচ্ছন্দ্যে মাপসই করে। একটি নতুন "শুরু থেকে পুনরুক্তি" (খুব লাইটওয়েট এবং কম ওভারহেড) যে কোনও সময়ে তৈরি করা যেতে পারে iter(L)এবং নতুন বা বিদ্যমানগুলি প্রভাবিত না করে অংশে বা পুরোপুরি ব্যবহার করা যেতে পারে ; অন্যান্য অ্যাক্সেস নিদর্শনগুলি সহজেই উপলব্ধ।

বিভিন্ন উত্তর ন্যায়ত মন্তব্য হিসেবে নির্দিষ্ট ক্ষেত্রে csvআপনি এটি করতে পারেন .seek(0)অন্তর্নিহিত ফাইল বস্তু (বরং একটি বিশেষ ক্ষেত্রে)। আমি নিশ্চিত নই যে এটি নথিভুক্ত এবং গ্যারান্টিযুক্ত, যদিও এটি বর্তমানে কাজ করে; এটি কেবলমাত্র সত্যিকারের বিশাল listসিএসভি ফাইলের জন্য বিবেচনা করা উপযুক্ত, যাতে আমি সাধারণ পদ্ধতির হিসাবে পুনঃসংশোধন করি যা একটি স্মৃতি পদক্ষেপ খুব বড় থাকে।


6
list()5MB ফাইলে একটি CSvreader এর উপর মাল্টিপ্যাসেজ ক্যাশে ব্যবহার করে আমার রানটাইমটি 12 সেকেন্ড থেকে 0.5 ডলারে যেতে দেখছে।
জন মে

33

আপনার কাছে যদি 'blah.csv' নামে একটি সিএসভি ফাইল থাকে তবে এটি দেখতে দেখতে ভাল লাগে

a,b,c,d
1,2,3,4
2,3,4,5
3,4,5,6

আপনি জানেন যে আপনি ফাইলটি পড়ার জন্য খুলতে পারেন এবং এর সাথে একটি ডিকট্রিডার তৈরি করতে পারেন

blah = open('blah.csv', 'r')
reader= csv.DictReader(blah)

তারপরে, আপনি পরবর্তী লাইনটি পেতে সক্ষম হবেন reader.next()যা আউটপুট হবে

{'a':1,'b':2,'c':3,'d':4}

এটি আবার ব্যবহার করে উত্পাদন হবে

{'a':2,'b':3,'c':4,'d':5}

তবে, আপনি যদি এই মুহূর্তে ব্যবহার করেন blah.seek(0), পরের বার আপনি কল reader.next()করবেন

{'a':1,'b':2,'c':3,'d':4}

আবার।

এটি আপনার সন্ধান করা কার্যকারিতা বলে মনে হচ্ছে। আমি নিশ্চিত যে এই পদ্ধতির সাথে কিছু কৌশল যুক্ত রয়েছে যা সম্পর্কে আমি অবগত নই। @ ব্রায়ান কেবলমাত্র অন্য একটি ডিকট্রিডার তৈরির পরামর্শ দিয়েছিল। আপনি যদি প্রথম পাঠক ফাইলটি পড়ার মাঝামাঝি দিকে যান তবে এটি কাজ করবে না, কারণ আপনার নতুন পাঠকের কাছে আপনি যেখানেই থাকুন ফাইল থেকে অপ্রত্যাশিত কী এবং মান থাকবে।


আমার তত্ত্বটি আমাকে এটাই বলেছিল, আমি যা দেখেছি তা ঘটবে তা দেখে ভাল লাগল।
ওয়েন ওয়ার্নার

@ উইলডাক: আপনি ডিকট্রিডার এর অন্য একটি উদাহরণের সাথে যে আচরণটি বর্ণনা করছেন তা ঘটবে না যদি আপনি একটি নতুন ফাইল হ্যান্ডেল তৈরি করেন এবং সেটি দ্বিতীয় ডিকট্রিডারকে দিয়ে দেন, তাই না?

আপনার যদি দুটি ফাইল হ্যান্ডলার থাকে তবে তারা স্বাধীনভাবে আচরণ করবে, হ্যাঁ।
ওয়াইল্ডক

24

নং পাইথনের ইটারেটর প্রোটোকলটি খুব সহজ, এবং কেবল একটি একক পদ্ধতি ( .next()বা __next__()) সরবরাহ করে এবং সাধারণভাবে কোনও পুনরুক্তি পুনরায় সেট করার কোনও পদ্ধতি সরবরাহ করে না।

সাধারণ প্যাটার্নটি হ'ল পরিবর্তে আবার একই পদ্ধতি ব্যবহার করে একটি নতুন পুনরাবৃত্তি তৈরি করা।

যদি আপনি কোনও পুনরুদ্ধারকারীকে "সংরক্ষণ" করতে চান যাতে আপনি এর শুরুতে ফিরে যেতে পারেন, আপনি পুনরুক্তিটি ব্যবহার করে কাঁটাচামচও করতে পারেন itertools.tee


1
আপনি .next () পদ্ধতিটি বিশ্লেষণ করার সময় সম্ভবত সঠিক, অপ্টটি যা চাচ্ছে তা পাওয়ার জন্য মোটামুটি সহজ উপায় রয়েছে।
ওয়াইল্ডক

2
@ উইলডাক: আমি দেখলাম যে আপনার উত্তর আমি কেবল পুনরাবৃত্তির প্রশ্নের উত্তর দিয়েছি, এবং csvমডিউল সম্পর্কে আমার কোনও ধারণা নেই । আশা করি দুটি উত্তরই মূল পোস্টারের কাজে আসবে।
u0b34a0f6ae

কঠোরভাবে, পুনরাবৃত্তকারী প্রোটোকলেরও প্রয়োজন __iter__। অর্থাৎ, পুনরাবৃত্তকারীদের পুনরাবৃত্ত হতে হবে।
স্টিভ জেসোপ

11

হ্যাঁ , আপনি যদি numpy.nditerনিজের পুনরুক্তি তৈরি করতে ব্যবহার করেন ।

>>> lst = [1,2,3,4,5]
>>> itr = numpy.nditer([lst])
>>> itr.next()
1
>>> itr.next()
2
>>> itr.finished
False
>>> itr.reset()
>>> itr.next()
1

nditerঅ্যারে মাধ্যমে চক্র করতে পারেন itertools.cycle?
LWZ

1
@LWZ: আমি তা মনে করি না, কিন্তু আপনি করতে পারেন এবং একটি উপর ব্যতিক্রম একটি । try:next()StopIterationreset()
পরবর্তী বিজ্ঞপ্তি না দেওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।


এটাই আমি খুঁজছিলাম!
শ্রীরাম

1
নোট করুন যে এখানে "অপারেন্ডস" এর সীমা 32: stackoverflow.com/questions/51856685/…
সাইমন

11

.seek(0)উপরে অ্যালেক্স মার্তেলি এবং ওয়াইল্ডাকের পক্ষে মতামত হিসাবে ব্যবহার করার ক্ষেত্রে একটি ত্রুটি রয়েছে, পরবর্তী কলটি আপনাকে .next()আপনার শিরোনাম সারিটির একটি অভিধান আকারে দেবে {key1:key1, key2:key2, ...}। চারপাশের কাজটি শিরোনাম সারি থেকে মুক্তি পাওয়ার file.seek(0)জন্য একটি কল অনুসরণ করা reader.next()

সুতরাং আপনার কোডটি এর মতো দেখতে লাগবে:

f_in = open('myfile.csv','r')
reader = csv.DictReader(f_in)

for record in reader:
    if some_condition:
        # reset reader to first row of data on 2nd line of file
        f_in.seek(0)
        reader.next()
        continue
    do_something(record)

5

এটি সম্ভবত মূল প্রশ্নের অর্থেগোনাল, তবে কেউ পুনরাবৃত্তিকে ফিরিয়ে দেয় এমন কোনও ফাংশনে পুনরায় আবরণ করতে পারে।

def get_iter():
    return iterator

পুনরাবৃত্তি পুনরায় সেট করতে কেবল ফাংশনটিতে আবার কল করুন। এটি অবশ্যই তুচ্ছ যদি ফাংশনটি যখন বলা ফাংশনটি কোনও আর্গুমেন্ট নেয় না।

যে ক্ষেত্রে ফাংশনটিতে কিছু যুক্তি প্রয়োজন, ফন্টাকুলগুলি ব্যবহার করুন a

def get_iter(arg1, arg2):
   return iterator
from functools import partial
iter_clos = partial(get_iter, a1, a2)

এটি টি (এন কপি) বা তালিকার (1 অনুলিপি) করতে হবে এমন ক্যাচিং এড়ানোর জন্য মনে হচ্ছে


3

ছোট ফাইলগুলির জন্য, আপনি ব্যবহার বিবেচনা করতে পারেন more_itertools.seekable- একটি তৃতীয় পক্ষের সরঞ্জাম যা পুনরায় সেটযোগ্য পুনরুদ্ধার অফার করে।

ডেমো

import csv

import more_itertools as mit


filename = "data/iris.csv"
with open(filename, "r") as f:
    reader = csv.DictReader(f)
    iterable = mit.seekable(reader)                    # 1
    print(next(iterable))                              # 2
    print(next(iterable))
    print(next(iterable))

    print("\nReset iterable\n--------------")
    iterable.seek(0)                                   # 3
    print(next(iterable))
    print(next(iterable))
    print(next(iterable))

আউটপুট

{'Sepal width': '3.5', 'Petal width': '0.2', 'Petal length': '1.4', 'Sepal length': '5.1', 'Species': 'Iris-setosa'}
{'Sepal width': '3', 'Petal width': '0.2', 'Petal length': '1.4', 'Sepal length': '4.9', 'Species': 'Iris-setosa'}
{'Sepal width': '3.2', 'Petal width': '0.2', 'Petal length': '1.3', 'Sepal length': '4.7', 'Species': 'Iris-setosa'}

Reset iterable
--------------
{'Sepal width': '3.5', 'Petal width': '0.2', 'Petal length': '1.4', 'Sepal length': '5.1', 'Species': 'Iris-setosa'}
{'Sepal width': '3', 'Petal width': '0.2', 'Petal length': '1.4', 'Sepal length': '4.9', 'Species': 'Iris-setosa'}
{'Sepal width': '3.2', 'Petal width': '0.2', 'Petal length': '1.3', 'Sepal length': '4.7', 'Species': 'Iris-setosa'}

এখানে ক DictReaderএকটি seekableঅবজেক্টে আবৃত (1) এবং উন্নত (2)। seek()পদ্ধতি রিসেট / 0th অবস্থান (3) এর পুনরুক্তিকারীর রিওয়াইন্ড করতে ব্যবহৃত হয়।

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


2

যখন কোনও পুনরায় পুনরায় সেট করা নেই, পাইথন ২.6 থেকে (এবং পরে) "ইটারটুলস" মডিউলটির কিছু ইউটিলিটি রয়েছে যা সেখানে সহায়তা করতে পারে। তার মধ্যে একটি হ'ল "টি" যা কোনও পুনরুক্তিকারীর একাধিক অনুলিপি তৈরি করতে পারে এবং এগিয়ে চলমানের ফলাফলগুলিকে ক্যাশে করতে পারে, যাতে এই ফলাফলগুলি অনুলিপিগুলিতে ব্যবহৃত হয়। আমি আপনার উদ্দেশ্যগুলি ছড়িয়ে দেব:

>>> def printiter(n):
...   for i in xrange(n):
...     print "iterating value %d" % i
...     yield i

>>> from itertools import tee
>>> a, b = tee(printiter(5), 2)
>>> list(a)
iterating value 0
iterating value 1
iterating value 2
iterating value 3
iterating value 4
[0, 1, 2, 3, 4]
>>> list(b)
[0, 1, 2, 3, 4]

1

ডিকট্রিডার এর জন্য:

f = open(filename, "rb")
d = csv.DictReader(f, delimiter=",")

f.seek(0)
d.__init__(f, delimiter=",")

ডিক্ট রাইটারের জন্য:

f = open(filename, "rb+")
d = csv.DictWriter(f, fieldnames=fields, delimiter=",")

f.seek(0)
f.truncate(0)
d.__init__(f, fieldnames=fields, delimiter=",")
d.writeheader()
f.flush()

1

list(generator()) একটি জেনারেটরের জন্য বাকী সমস্ত মান প্রদান করে এবং কার্যকরভাবে এটি পুনরায় সেট করে যদি এটি লুপ না করা হয়।


1

সমস্যা

আমার আগেও একই সমস্যা ছিল আমার কোডটি বিশ্লেষণ করার পরে, আমি বুঝতে পেরেছি যে লুপগুলির অভ্যন্তরে পুনরাবৃত্তকারীকে পুনরায় সেট করার চেষ্টা করা সময়ের জটিলতাটিকে কিছুটা বাড়িয়ে তোলে এবং এটি কোডটিকে কিছুটা কুৎসিত করে তোলে।

সমাধান

ফাইলটি খুলুন এবং সারিগুলিকে মেমরির একটি ভেরিয়েবলে সংরক্ষণ করুন।

# initialize list of rows
rows = []

# open the file and temporarily name it as 'my_file'
with open('myfile.csv', 'rb') as my_file:

    # set up the reader using the opened file
    myfilereader = csv.DictReader(my_file)

    # loop through each row of the reader
    for row in myfilereader:
        # add the row to the list of rows
        rows.append(row)

এখন আপনি কোনও পুনরুক্তিকারীর সাথে লেনদেন ছাড়াই আপনার সুযোগের যে কোনও জায়গায় সারিগুলি লুপ করতে পারেন ।


1

একটি সম্ভাব্য বিকল্প হ'ল ব্যবহার করা itertools.cycle(), যা আপনাকে কোনও কৌশল না করে অনির্দিষ্টকালের জন্য পুনরাবৃত্তি করতে দেয় .seek(0)

iterDic = itertools.cycle(csv.DictReader(open('file.csv')))

1

আমি এই একই ইস্যুতে পৌঁছে যাচ্ছি - আমি যখন tee()সমাধানটি পছন্দ করি তখনও আমার ফাইলগুলি কত বড় হতে চলেছে তা আমি জানি না এবং অন্যটির আগে প্রথমে একটিকে গ্রাস করার বিষয়ে মেমরির সতর্কতা আমাকে সেই পদ্ধতিটি অবলম্বন করতে ছাড়ছে।

পরিবর্তে, আমি iter()স্টেটমেন্টগুলি ব্যবহার করে এবং চূড়ান্ত রানের জন্য দ্বিতীয়টিতে স্যুইচ করার আগে আমার প্রথম রান-থ্রোয়ের জন্য প্রথমটি ব্যবহার করছি ite

সুতরাং, ডিক্ট-রিডারের ক্ষেত্রে যদি পাঠককে এটি ব্যবহার করে সংজ্ঞায়িত করা হয়:

d = csv.DictReader(f, delimiter=",")

আমি এই "স্পেসিফিকেশন" থেকে পুনরাবৃত্তকারীদের একটি জুড়ি তৈরি করতে পারি - এটি ব্যবহার করে:

d1, d2 = iter(d), iter(d)

তারপরে আমি আমার প্রথম পাসের কোডটি চালাতে পারি d1, দ্বিতীয় d2রুটটি একই রুট স্পেসিফিকেশন থেকে সংজ্ঞায়িত করা হয়েছে এই জ্ঞানে নিরাপদ ।

আমি এটিকে পুরোপুরি পরীক্ষা করে দেখিনি, তবে এটি ডামি ডেটা দিয়ে কাজ করে বলে মনে হচ্ছে।


0

অন্তর্নিহিত প্রকারটি যদি এর জন্য কোনও প্রক্রিয়া সরবরাহ করে তবেই (উদাঃ fp.seek(0))।


0

'ইটার ()' কল চলাকালীন সর্বশেষ পুনরাবৃত্তিতে একটি নতুন নির্মিত পুনরাবৃত্তি ফিরিয়ে দিন

class ResetIter: 
  def __init__(self, num):
    self.num = num
    self.i = -1

  def __iter__(self):
    if self.i == self.num-1: # here, return the new object
      return self.__class__(self.num) 
    return self

  def __next__(self):
    if self.i == self.num-1:
      raise StopIteration

    if self.i <= self.num-1:
      self.i += 1
      return self.i


reset_iter = ResetRange(10)
for i in reset_iter:
  print(i, end=' ')
print()

for i in reset_iter:
  print(i, end=' ')
print()

for i in reset_iter:
  print(i, end=' ')

আউটপুট:

0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.