পাইথনের একটি পুনরাবৃত্তিতে সাধারণভাবে প্রতিটি দ্বারা পুনরাবৃত্তি এবং গণনা ছাড়াই কতগুলি উপাদান রয়েছে তা জানার কোনও কার্যকর উপায় আছে?
পাইথনের একটি পুনরাবৃত্তিতে সাধারণভাবে প্রতিটি দ্বারা পুনরাবৃত্তি এবং গণনা ছাড়াই কতগুলি উপাদান রয়েছে তা জানার কোনও কার্যকর উপায় আছে?
উত্তর:
না এটা সম্ভব নয়
উদাহরণ:
import random
def gen(n):
for i in xrange(n):
if random.randint(0, 1) == 0:
yield i
iterator = gen(10)
iterator
আপনি এটির মাধ্যমে পুনরাবৃত্তি না হওয়া পর্যন্ত দৈর্ঘ্যের অজানা।
def gen(): yield random.randint(0, 1)
অসীম, সুতরাং আপনি এর মাধ্যমে পুনরাবৃত্তি করে কোনও দৈর্ঘ্য খুঁজে পেতে সক্ষম হবেন না।
numIters = 0 ; while iterator: numIters +=1
?
এই কোডটি কাজ করা উচিত:
>>> iter = (i for i in range(50))
>>> sum(1 for _ in iter)
50
যদিও এটি প্রতিটি আইটেমের মাধ্যমে পুনরাবৃত্তি করে এবং তাদের গণনা করে, এটি এটি করার দ্রুততম উপায়।
যখন পুনরাবৃত্তকারীটির কোনও আইটেম না থাকে তখন এটি কাজ করে:
>>> sum(1 for _ in range(0))
0
অবশ্যই এটি অসীম ইনপুটটির জন্য চিরকাল চলে, সুতরাং মনে রাখবেন যে পুনরাবৃত্তিগুলি অসীম হতে পারে:
>>> sum(1 for _ in itertools.count())
[nothing happens, forever]
এছাড়াও, সচেতন থাকুন যে এটির দ্বারা পুনরুক্তিকারী ক্লান্ত হয়ে যাবে এবং এর ব্যবহারের আরও চেষ্টাগুলি কোনও উপাদান দেখতে পাবে না । এটি পাইথন ইটারেটর ডিজাইনের একটি অনিবার্য পরিণতি। আপনি যদি উপাদানগুলি রাখতে চান তবে আপনাকে সেগুলি একটি তালিকা বা অন্য কিছুতে সংরক্ষণ করতে হবে।
_
পার্লের রেফারেন্স কি $_
? :)
_
একটি ডামি ভেরিয়েবলের জন্য নামটি ব্যবহার করার জন্য পাইথনের মধ্যে প্রচলিত, যার মান আপনি পছন্দ করেন না।
না, যে কোনও পদ্ধতিতে আপনার প্রতিটি ফলাফল সমাধান করা দরকার। আপনি করতে পারেন
iter_length = len(list(iterable))
তবে এটি অসীম পুনরাবৃত্তকারী চালানো অবশ্যই কখনই ফিরে আসবে না। এটি পুনরাবৃত্তিকে গ্রাস করবে এবং আপনি সামগ্রীগুলি ব্যবহার করতে চাইলে এটি পুনরায় সেট করতে হবে।
আপনি কোন আসল সমস্যাটি সমাধান করার চেষ্টা করছেন তা আমাদের জানানোর মাধ্যমে আপনার প্রকৃত লক্ষ্য অর্জনের আরও ভাল উপায় খুঁজে পেতে আমাদের সহায়তা করতে পারে।
সম্পাদনা করুন: list()
ব্যবহারটি সম্পূর্ণ পুনরাবৃত্তিকে মেমরিতে একবারে পড়বে, যা অনাকাঙ্ক্ষিত হতে পারে। আরেকটি উপায় হয়
sum(1 for _ in iterable)
অন্য একজন পোস্ট করা হিসাবে। এটি এটিকে স্মৃতিতে রাখা এড়াবে।
len(list(iterable))
এটি ব্যবহার করবেন না সমস্ত ডেটা মেমরিতে লোড করবে। আপনি ব্যবহার করতে পারেন: reduce(lambda x, _: x+1, iterable, 0)
। সম্পাদনা করুন: যোগফল সহ জন্ডা 333 কোডটিও ভাল।
functools.reduce
আপনি পারবেন না (কোনও নির্দিষ্ট পুনরাবৃত্তকারীর প্রকার ব্যতীত কিছু নির্দিষ্ট পদ্ধতি কার্যকর করে যা এটি সম্ভব করে)।
সাধারণত, আপনি কেবল আয়রেটর গ্রাস করে পুনরুক্তি আইটেমগুলি গণনা করতে পারেন। সম্ভবত সবচেয়ে কার্যকর উপায়গুলির মধ্যে একটি:
import itertools
from collections import deque
def count_iter_items(iterable):
"""
Consume an iterable not reading it into memory; return the number of items.
"""
counter = itertools.count()
deque(itertools.izip(iterable, counter), maxlen=0) # (consume at C speed)
return next(counter)
(জন্য পাইথন প্রতিস্থাপন 3.x itertools.izip
সঙ্গে zip
)।
sum(1 for _ in iterator)
এটি প্রায় দ্বিগুণ দ্রুত ছিল।
zip
: যদি আপনি পাস করেন তবে আপনি zip(counter, iterable)
আসলে পুনরাবৃত্ত গণনার চেয়ে আরও 1 টি পাবেন!
ধরণ. আপনি পদ্ধতিটি পরীক্ষা করে দেখতে পারেন__length_hint__
, তবে সতর্ক হতে হবে (কমপক্ষে পাইথন ৩.৪ অবধি, যেমন gsnedders সহায়তার সাথে উল্লেখ করে) এটি একটি অনিবন্ধিত বাস্তবায়ন বিশদ ( থ্রেডের বার্তায় নিম্নলিখিত ), এটি খুব ভালভাবে বিলুপ্ত বা অনুনাসিক রাক্ষসদের আহ্বান করতে পারে।
অন্যথায়, না। আইট্রেটারগুলি কেবল একটি অবজেক্ট যা কেবল next()
পদ্ধতিটি প্রকাশ করে । আপনি এটিকে যতবার প্রয়োজন কল করতে পারেন এবং তারা শেষ পর্যন্ত বাড়াতেও পারে বা নাও পারে StopIteration
। ভাগ্যক্রমে, এই আচরণটি কোডারের কাছে বেশিরভাগ সময় স্বচ্ছ। :)
আমি এর জন্য কার্ডিনালিটি প্যাকেজটি পছন্দ করি , এটি খুব স্বল্প ওজনের এবং পুনরাবৃত্তির উপর নির্ভর করে উপলব্ধ দ্রুততম বাস্তবায়নটি ব্যবহার করার চেষ্টা করে।
ব্যবহার:
>>> import cardinality
>>> cardinality.count([1, 2, 3])
3
>>> cardinality.count(i for i in range(500))
500
>>> def gen():
... yield 'hello'
... yield 'world'
>>> cardinality.count(gen())
2
আসল count()
বাস্তবায়ন নিম্নরূপ:
def count(iterable):
if hasattr(iterable, '__len__'):
return len(iterable)
d = collections.deque(enumerate(iterable, 1), maxlen=1)
return d[0][0] if d else 0
সুতরাং, যারা এই আলোচনার সংক্ষিপ্তসার জানতে চান তাদের জন্য। 50 মিলিয়ন দৈর্ঘ্যের জেনারেটর এক্সপ্রেশন ব্যবহার করে চূড়ান্ত শীর্ষস্থানীয় স্কোরগুলি:
len(list(gen))
, len([_ for _ in gen])
, sum(1 for _ in gen),
ilen(gen)
( মোর_সিটারোল থেকে ),reduce(lambda c, i: c + 1, gen, 0)
, সম্পাদনের কার্য সম্পাদন (মেমরির খরচ সহ) অনুসারে বাছাই করা আপনাকে অবাক করে দেবে:
``
gen = (i for i in data*1000); t0 = monotonic(); len(list(gen))
('তালিকা, সেকেন্ড', 1.9684218849870376)
gen = (i for i in data*1000); t0 = monotonic(); len([i for i in gen])
('তালিকা_কমপ্রি, সেকেন্ড', 2.5885991149989422)
gen = (i for i in data*1000); t0 = monotonic(); sum(1 for i in gen); t1 = monotonic()
('যোগফল, সেকেন্ড', 3.441088170016883)
d = deque(enumerate(iterable, 1), maxlen=1)
test_ilen.py:10: 0.875 KiB
gen = (i for i in data*1000); t0 = monotonic(); ilen(gen)
('ইলেন, সেকেন্ড', 9.812256851990242)
gen = (i for i in data*1000); t0 = monotonic(); reduce(lambda counter, i: counter + 1, gen, 0)
('হ্রাস, সেকেন্ড', 13.436614598002052) `` ``
সুতরাং, len(list(gen))
সর্বাধিক ঘন এবং কম স্মৃতি গ্রাহ্যযোগ্য
len(list(gen))
হ্রাসের ভিত্তিতে পদ্ধতির চেয়ে কম স্মৃতি গ্রহণ করা উচিত? প্রাক্তন একটি নতুন তৈরি করে list
যা মেমোরি বরাদ্দকে জড়িত করে যখন এর পরে না করা উচিত। সুতরাং আমি আশা করব যে আধুনিকগুলি আরও মেমরির দক্ষ হবে। এছাড়াও, মেমরির খরচ উপাদান ধরণের উপর নির্ভর করবে।
len(tuple(iterable))
আরও কার্যকর হতে পারে: নেলসন মিনার দ্বারা নিবন্ধ
একটি পুনরাবৃত্তি হ'ল কেবল এমন একটি অবজেক্ট যা পরবর্তী অবজেক্টের পয়েন্টারযুক্ত কোনও ধরণের বাফার বা স্ট্রিমের দ্বারা পড়তে পারে, এটি একটি লিংকডলিস্টের মতো যেখানে আপনি জানেন না যে আপনার কাছে কতগুলি জিনিস রয়েছে যতক্ষণ না সেগুলি পুনরাবৃত্তি না করেন। আইট্রেটাররা দক্ষ হওয়ার জন্য বোঝায় কারণ তারা যা কিছু করেন তা সূচকগুলি ব্যবহার না করে রেফারেন্সের পরে কী হয় তা আপনাকে জানান (তবে আপনি দেখতে পেয়েছিলেন যে পরবর্তী কয়টি এন্ট্রি রয়েছে তা দেখার ক্ষমতা হারাতে পারেন)।
আপনার আসল প্রশ্নটি সম্পর্কে, উত্তরটি এখনও রয়েছে যে পাইথনের কোনও পুনরাবৃত্তির দৈর্ঘ্য জানার কোনও উপায় নেই।
আপনার প্রশ্নটি পাইসাম লাইব্রেরির একটি অ্যাপ্লিকেশন দ্বারা অনুপ্রাণিত হয়েছে তা প্রদত্ত, আমি আরও একটি সুনির্দিষ্ট উত্তর দিতে পারি: আমি পাইস্যামের একজন সহযোগী এবং এর সুনির্দিষ্ট উত্তর হ'ল এসএএম / বিএএম ফাইলগুলি সারিবদ্ধ পাঠকের সঠিক গণনা সরবরাহ করে না। বা বিএএম সূচক ফাইল থেকে এই তথ্য সহজেই পাওয়া যায় না। সবচেয়ে ভাল যা করতে পারে তা হল ফাইলের মোট আকারের উপর ভিত্তি করে অ্যালাইনমেন্টের অনেকগুলি সংখ্যা পড়ার পরে ফাইল পয়েন্টারের অবস্থান ব্যবহার করে এবং প্রান্তিককরণের আনুমানিক সংখ্যার অনুমান করা। এটি একটি অগ্রগতি বার বাস্তবায়নের জন্য যথেষ্ট, তবে ধ্রুব সময়ে অ্যালাইনমেন্ট গণনা করার কোনও পদ্ধতি নয়।
একটি দ্রুত মানদণ্ড:
import collections
import itertools
def count_iter_items(iterable):
counter = itertools.count()
collections.deque(itertools.izip(iterable, counter), maxlen=0)
return next(counter)
def count_lencheck(iterable):
if hasattr(iterable, '__len__'):
return len(iterable)
d = collections.deque(enumerate(iterable, 1), maxlen=1)
return d[0][0] if d else 0
def count_sum(iterable):
return sum(1 for _ in iterable)
iter = lambda y: (x for x in xrange(y))
%timeit count_iter_items(iter(1000))
%timeit count_lencheck(iter(1000))
%timeit count_sum(iter(1000))
ফলাফলগুলো:
10000 loops, best of 3: 37.2 µs per loop
10000 loops, best of 3: 47.6 µs per loop
10000 loops, best of 3: 61 µs per loop
অর্থাত্ সরল কাউন্টি_ইটার_াইটেমগুলি হ'ল উপায়।
পাইথন 3 এর জন্য এটি সামঞ্জস্য করা:
61.9 µs ± 275 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
74.4 µs ± 190 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
82.6 µs ± 164 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
কম্পিউটারে "কিছু" দৈর্ঘ্য পাওয়ার দুটি উপায় রয়েছে।
প্রথম উপায়টি একটি গণনা সংরক্ষণ করা - এটির পরিবর্তনের জন্য ফাইল / ডেটা স্পর্শ করার জন্য এমন কোনও কিছু প্রয়োজন (বা এমন একটি শ্রেণি যা কেবল ইন্টারফেসগুলি প্রকাশ করে - তবে এটি একই জিনিসটিতে ফোটে)।
অন্য উপায়টি হল এটির উপরে পুনরাবৃত্তি এবং এটি কত বড় তা গণনা করা।
এটি কোনও পুনরাবৃত্তির খুব সংজ্ঞাবিরোধী, যা কোনও বস্তুর পয়েন্টার এবং পরবর্তী বস্তুতে কীভাবে পাবেন সে সম্পর্কে তথ্য information
একজন পুনরুক্তিকারী জানেন না যে এটি সমাপ্ত না হওয়া পর্যন্ত আরও কতবার পুনরাবৃত্তি করতে সক্ষম হবে। এটি অসীম হতে পারে, তাই অনন্ত আপনার উত্তর হতে পারে।
যদিও যা বলা হয়েছে তা করা সাধারণভাবে সম্ভব নয়, তবুও প্রায়শই কতগুলি আইটেমগুলি পুনরাবৃত্ত হওয়ার পরে তার পুনরাবৃত্তি হয়েছিল তা গণনা করা বেশ কার্যকর । তার জন্য, আপনি jaraco.itertools.Cauter বা অনুরূপ ব্যবহার করতে পারেন । পাইথন 3 এবং প্যাকেজটি লোড করতে rwt ব্যবহার করার একটি উদাহরণ এখানে ।
$ rwt -q jaraco.itertools -- -q
>>> import jaraco.itertools
>>> items = jaraco.itertools.Counter(range(100))
>>> _ = list(counted)
>>> items.count
100
>>> import random
>>> def gen(n):
... for i in range(n):
... if random.randint(0, 1) == 0:
... yield i
...
>>> items = jaraco.itertools.Counter(gen(100))
>>> _ = list(counted)
>>> items.count
48
সম্ভবত, আপনি পুনরাবৃত্তি না করে আইটেমের সংখ্যা গণনা করতে চান, যাতে পুনরাবৃত্তিটি নিঃশেষ না হয় এবং আপনি এটি পরে আবার ব্যবহার করেন। copy
বা দিয়ে সম্ভবdeepcopy
import copy
def get_iter_len(iterator):
return sum(1 for _ in copy.copy(iterator))
###############################################
iterator = range(0, 10)
print(get_iter_len(iterator))
if len(tuple(iterator)) > 1:
print("Finding the length did not exhaust the iterator!")
else:
print("oh no! it's all gone")
আউটপুট " Finding the length did not exhaust the iterator!
"
Andচ্ছিকভাবে (এবং উদ্বেগহীনভাবে), আপনি len
নিম্নরূপে বিল্ট-ইন ফাংশনটিকে ছায়া দিতে পারেন :
import copy
def len(obj, *, len=len):
try:
if hasattr(obj, "__len__"):
r = len(obj)
elif hasattr(obj, "__next__"):
r = sum(1 for _ in copy.copy(obj))
else:
r = len(obj)
finally:
pass
return r
map
ফলাফল পুনরায় ফাংশন কল একবারে ঘটবে বলে প্রত্যাশা করে একজন পুনরাবৃত্তি করলেন।