পূর্ণসংখ্যার একটি তালিকা দেওয়া, আমি খুঁজে পেতে চাই যে ইনপুটটিতে দেওয়া সংখ্যার নিকটতম সংখ্যাটি:
>>> myList = [4, 1, 88, 44, 3]
>>> myNumber = 5
>>> takeClosest(myList, myNumber)
...
4
এটি করার কোনও দ্রুত উপায় আছে?
পূর্ণসংখ্যার একটি তালিকা দেওয়া, আমি খুঁজে পেতে চাই যে ইনপুটটিতে দেওয়া সংখ্যার নিকটতম সংখ্যাটি:
>>> myList = [4, 1, 88, 44, 3]
>>> myNumber = 5
>>> takeClosest(myList, myNumber)
...
4
এটি করার কোনও দ্রুত উপায় আছে?
উত্তর:
যদি আমরা নিশ্চিত না হয়েছি যে তালিকাটি সাজানো হয়েছে তবে আমরা অন্তর্নির্মিত min()
ফাংশনটি ব্যবহার করতে পারব , নির্দিষ্ট উপাদান থেকে ন্যূনতম দূরত্ব রয়েছে এমন উপাদানটি সন্ধান করতে।
>>> min(myList, key=lambda x:abs(x-myNumber))
4
মনে রাখবেন যে এছাড়াও, int- এ কী এর মাধ্যমে dicts সাথে কাজ করে মত {1: "a", 2: "b"}
। এই পদ্ধতিতে ও (এন) সময় লাগে।
যদি তালিকাটি ইতিমধ্যে বাছাই করা থাকে, বা আপনি একবারে অ্যারে বাছাইয়ের মূল্য দিতে পারেন তবে @ লরিৎজসের উত্তরে বর্ণিত দ্বিখণ্ডিত পদ্ধতিটি ব্যবহার করুন যা কেবল ও (লগ এন) সময় নেয় (নোট তবে পরীক্ষার তালিকা ইতিমধ্যে বাছাই করা হয়েছে কিনা ও (এন) এবং বাছাই হয় হে (এন লগ এন))
O(n)
যেখানে সামান্য হ্যাকিং bisect
আপনাকে একটি বৃহত উন্নতি দেবে O(log n)
(যদি আপনার ইনপুট অ্যারেটি সাজানো থাকে)।
min
, items()
তালিকার পরিবর্তে অভিধান ( ) এ এটি চালান , এবং শেষে মানটির পরিবর্তে কীটি ফিরিয়ে দিন।
আমি take_closest
পিইপি 8 নামকরণ কনভেনশনগুলির সাথে সামঞ্জস্য করতে ফাংশনটির নাম পরিবর্তন করব ।
দ্রুত-লেখার বিরোধী হিসাবে যদি আপনি দ্রুত-মৃত্যুদন্ড কার্যকর করতে চান, তবে খুব সংকীর্ণ ব্যবহারের ক্ষেত্রে বাদে আপনার পছন্দের অস্ত্র min
হওয়া উচিত নয় । min
সমাধান তালিকায় প্রতি NUMBER পরীক্ষা করার প্রয়োজন এবং প্রতিটি সংখ্যার জন্য একটি গণনা করা যাক। bisect.bisect_left
পরিবর্তে ব্যবহার করা প্রায় সবসময় দ্রুত হয়।
"প্রায়" সত্যটি আসে bisect_left
যা তালিকাকে কাজ অনুসারে বাছাই করা প্রয়োজন। আশা করা যায়, আপনার ব্যবহারের কেসটি এমন যে আপনি একবার তালিকাটি বাছাই করতে পারেন এবং তারপরে এটিকে একা রেখে যান। তা না পারলেও যতক্ষণ আপনার কল করার আগে যতক্ষণ বাছাই করার দরকার নেই take_closest
, bisect
মডিউলটি সম্ভবত উপরে চলে আসবে। যদি আপনার সন্দেহ হয় তবে দু'জনেই চেষ্টা করুন এবং বাস্তব-বিশ্বের পার্থক্যটি দেখুন।
from bisect import bisect_left
def take_closest(myList, myNumber):
"""
Assumes myList is sorted. Returns closest value to myNumber.
If two numbers are equally close, return the smallest number.
"""
pos = bisect_left(myList, myNumber)
if pos == 0:
return myList[0]
if pos == len(myList):
return myList[-1]
before = myList[pos - 1]
after = myList[pos]
if after - myNumber < myNumber - before:
return after
else:
return before
বিস্কিট বারবার একটি তালিকা অর্ধেক myNumber
করে মধ্যম মানেরটি দেখে কোনটি অর্ধেকের মধ্যে থাকতে হবে তা খুঁজে বের করে কাজ করে । এর অর্থ এটি ও (লগ এন) এর চলমান সময় হিসাবে সর্বোচ্চ ভোট প্রাপ্ত উত্তরের ও (এন) চলমান সময়ের বিপরীতে রয়েছে । যদি আমরা দুটি পদ্ধতির তুলনা করি এবং উভয়কে বাছাই করে সরবরাহ করি তবে myList
এগুলি ফলাফল:
"পাইথন-মি টাইমিট-এস" নিকটতম আমদানি থেকে_ক্লোজস্ট থেকে এলোমেলো আমদানি র্যান্ড্যান্ড থেকে a = পরিসর (-1000, 1000, 10) "" নিন_ক্লোজস্ট (এ, র্যান্ডিন্ট (-1100, 1100)) " 100000 লুপ, প্রতি লুপে 3: 2.22 ব্যবহারের সেরা "পাইথন-মি টাইমিট-এস" _মিনের সাথে নিকটতম আমদানি থেকে এলোমেলো আমদানি র্যান্ড্যান্ড থেকে a = পরিসর (-1000, 1000, 10) "" সাথে_মিনি (একটি, র্যান্ডেন্ট (-1100, 1100)) " 10000 লুপ, লুপ প্রতি 3: 43.9 ব্যবহারকারীর মধ্যে সেরা
সুতরাং এই বিশেষ পরীক্ষায়, bisect
প্রায় 20 গুণ দ্রুত হয়। দীর্ঘ তালিকার জন্য, পার্থক্য আরও বেশি হবে।
আমরা যদি পূর্বের শর্তটি myList
বাছাই করতে হবে তা সরিয়ে প্লেয়িং ফিল্ডকে সমতল করি ? আসুন আমরা সমাধানটি অবিচ্ছিন্ন অবস্থায় ছেড়ে যাওয়ার সময় তালিকার অনুলিপিটি প্রতিবারই সাজানো বলি । উপরের পরীক্ষায় 200-আইটেমের তালিকাটি ব্যবহার করে, সমাধানটি এখনও সবচেয়ে দ্রুত, যদিও কেবল 30% দ্বারা।take_closest
min
bisect
এটি একটি অদ্ভুত ফলাফল, বিবেচনা করে বাছাইকরণ পদক্ষেপটি হে (এন লগ (এন)) ! min
এখনও হারানোর একমাত্র কারণ হ'ল বাছাইটি অত্যন্ত অনুকূল সি কোডে করা হয়, যখন min
প্রতিটি আইটেমের জন্য ল্যাম্বডা ফাংশন কল করার পাশাপাশি প্লড করতে হয়। হিসাবে myList
আকার বৃদ্ধি, min
সমাধান অবশেষে দ্রুততর হবে। নোট করুন যে min
জয়ের সমাধানের জন্য আমাদের সবকিছু তার পক্ষে ছিল ।
a=range(-1000,1000,2);random.shuffle(a)
এটি takeClosest(sorted(a), b)
ধীর হয়ে উঠবে।
getClosest
না প্রতিটি ধরণের জন্য একাধিকবার ডাকা যেতে পারে, এটি দ্রুত হবে এবং সারণে-একবার ব্যবহারের ক্ষেত্রে এটি কোনও মস্তিষ্কের নয়।
myList
ইতিমধ্যে একটি হয় np.array
তাহলে ব্যবহারnp.searchsorted
এর জায়গায়bisect
করা দ্রুত।
>>> takeClosest = lambda num,collection:min(collection,key=lambda x:abs(x-num))
>>> takeClosest(5,[4,1,88,44,3])
4
একটি লাম্বদা একটি "বেনামি" ফাংশন (একটি ফাংশন যার নাম নেই) লেখার একটি বিশেষ উপায়। আপনি এটি যে কোনও নাম নির্ধারণ করতে পারেন কারণ ল্যাম্বডা একটি অভিব্যক্তি।
উপরের লেখার "দীর্ঘ" উপায়টি হ'ল:
def takeClosest(num,collection):
return min(collection,key=lambda x:abs(x-num))
def closest(list, Number):
aux = []
for valor in list:
aux.append(abs(Number-valor))
return aux.index(min(aux))
এই কোডটি আপনাকে তালিকার নিকটতম সংখ্যার সূচক দেবে।
কেনিনিটিএম প্রদত্ত সমাধানটি সামগ্রিকভাবে সেরা, তবে যে ক্ষেত্রে আপনি এটি ব্যবহার করতে পারবেন না (ব্রাইথনের মতো), এই ফাংশনটি কাজটি করবে
তালিকাটি পরীক্ষা করে দেখুন এবং বর্তমান নিকটতম সংখ্যার সাথে তুলনা করুন abs(currentNumber - myNumber)
:
def takeClosest(myList, myNumber):
closest = myList[0]
for i in range(1, len(myList)):
if abs(i - myNumber) < closest:
closest = i
return closest
if abs(myList[i] - myNumber) < abs(closest - myNumber): closest = myList[i];
। যদিও আগে ভাল মান ভাল স্টোর।
এটি লক্ষণীয় গুরুত্বপূর্ণ যে বাইসেক্ট ব্যবহারের জন্য লরিৎজের পরামর্শ ধারণাটি মাইলিস্ট থেকে মাইম্বরের নিকটতম মানটি খুঁজে পায় না। পরিবর্তে, দ্বিখণ্ডিত করা পরবর্তী মান খুঁজে বের করে অর্ডার MyList মধ্যে MyNumber পরে। সুতরাং ওপির ক্ষেত্রে আপনি 4 অবস্থানের পরিবর্তে 44 অবস্থান ফিরে পাবেন returned
>>> myList = [1, 3, 4, 44, 88]
>>> myNumber = 5
>>> pos = (bisect_left(myList, myNumber))
>>> myList[pos]
...
44
5 এর নিকটতম মানটি পেতে আপনি তালিকাটিকে একটি অ্যারেতে রূপান্তর করতে এবং এর মতো ন্যাক্পি থেকে আরগমিন ব্যবহার করার চেষ্টা করতে পারেন।
>>> import numpy as np
>>> myNumber = 5
>>> myList = [1, 3, 4, 44, 88]
>>> myArray = np.array(myList)
>>> pos = (np.abs(myArray-myNumber)).argmin()
>>> myArray[pos]
...
4
আমি জানি না যদিও এটি কতটা দ্রুত হবে, আমার অনুমান "খুব বেশি নয়"।
np.searchsorted
পরিবর্তে ব্যবহার করতে পারেন bisect_left
। এবং কানাট ঠিক বলেছেন - লরিটসের সমাধানে এমন দুটি কোড রয়েছে যা দুটি প্রার্থীর মধ্যে কাছাকাছি কোনটি বেছে নেয়।
গুস্তাভো লিমার উত্তরের প্রসার বাড়ানো। সম্পূর্ণ নতুন তালিকা তৈরি না করে একই জিনিসটি করা যেতে পারে। FOR
লুপের অগ্রগতির সাথে তালিকার মানগুলি ডিফারেনশিয়ালের সাথে প্রতিস্থাপন করা যেতে পারে ।
def f_ClosestVal(v_List, v_Number):
"""Takes an unsorted LIST of INTs and RETURNS INDEX of value closest to an INT"""
for _index, i in enumerate(v_List):
v_List[_index] = abs(v_Number - i)
return v_List.index(min(v_List))
myList = [1, 88, 44, 4, 4, -2, 3]
v_Num = 5
print(f_ClosestVal(myList, v_Num)) ## Gives "3," the index of the first "4" in the list.
যদি আমি @ লরিৎস এর উত্তর যোগ করতে পারি
রান ত্রুটি না হওয়ার জন্য bisect_left
লাইনের আগে একটি শর্ত যুক্ত করতে ভুলবেন না :
if (myNumber > myList[-1] or myNumber < myList[0]):
return False
সুতরাং সম্পূর্ণ কোডটি দেখতে পাবেন:
from bisect import bisect_left
def takeClosest(myList, myNumber):
"""
Assumes myList is sorted. Returns closest value to myNumber.
If two numbers are equally close, return the smallest number.
If number is outside of min or max return False
"""
if (myNumber > myList[-1] or myNumber < myList[0]):
return False
pos = bisect_left(myList, myNumber)
if pos == 0:
return myList[0]
if pos == len(myList):
return myList[-1]
before = myList[pos - 1]
after = myList[pos]
if after - myNumber < myNumber - before:
return after
else:
return before