गति के लिए तार की पार्स सूची
पृष्ठभूमि
मेरे पास एक फ़ंक्शन है जिसे get_player_path
स्ट्रिंग्स player_file_list
और एक इंट वैल्यू की सूची में लिया जाता है total_players
। उदाहरण के लिए मैंने स्ट्रिंग्स की सूची को कम कर दिया है और बहुत कम संख्या के लिए अंतर मूल्य भी निर्धारित किया है।
player_file_list
या तो प्रत्येक स्ट्रिंग में एक year-date/player_id/some_random_file.file_extension
या हैyear-date/player_id/IDATs/some_random_number/some_random_file.file_extension
मुद्दा
मैं यहाँ प्राप्त करने के लिए अनिवार्य रूप से कोशिश कर रहा हूँ, इस सूची से गुजरना है और year-date/player_id
एक सेट में सभी अद्वितीय पथ को तब तक संग्रहीत करना है जब तक कि यह लम्बाई के मूल्य तक न पहुँच जाएtotal_players
मेरा वर्तमान दृष्टिकोण मुझे सबसे अधिक कुशल नहीं लगता है और मैं सोच रहा हूं कि क्या मैं किसी get_player_path
भी तरह से अपने कार्य को गति दे सकता हूं ??
कोड
def get_player_path(player_file_list, total_players):
player_files_to_process = set()
for player_file in player_file_list:
player_file = player_file.split("/")
file_path = f"{player_file[0]}/{player_file[1]}/"
player_files_to_process.add(file_path)
if len(player_files_to_process) == total_players:
break
return sorted(player_files_to_process)
player_file_list = [
"2020-10-27/31001804320549/31001804320549.json",
"2020-10-27/31001804320549/IDATs/204825150047/foo_bar_Red.idat",
"2020-10-28/31001804320548/31001804320549.json",
"2020-10-28/31001804320548/IDATs/204825150123/foo_bar_Red.idat",
"2020-10-29/31001804320547/31001804320549.json",
"2020-10-29/31001804320547/IDATs/204825150227/foo_bar_Red.idat",
"2020-10-30/31001804320546/31001804320549.json",
"2020-10-30/31001804320546/IDATs/123455150047/foo_bar_Red.idat",
"2020-10-31/31001804320545/31001804320549.json",
"2020-10-31/31001804320545/IDATs/597625150047/foo_bar_Red.idat",
]
print(get_player_path(player_file_list, 2))
उत्पादन
['2020-10-27/31001804320549/', '2020-10-28/31001804320548/']
जवाब
मैं इस समाधान को यहाँ छोड़ दूँगा जिसे और बेहतर बनाया जा सकता है, आशा है कि यह मदद करेगा।
player_file_list = (
"2020-10-27/31001804320549/31001804320549.json",
"2020-10-27/31001804320549/IDATs/204825150047/foo_bar_Red.idat",
"2020-10-28/31001804320548/31001804320549.json",
"2020-10-28/31001804320548/IDATs/204825150123/foo_bar_Red.idat",
"2020-10-29/31001804320547/31001804320549.json",
"2020-10-29/31001804320547/IDATs/204825150227/foo_bar_Red.idat",
"2020-10-30/31001804320546/31001804320549.json",
"2020-10-30/31001804320546/IDATs/123455150047/foo_bar_Red.idat",
"2020-10-31/31001804320545/31001804320549.json",
"2020-10-31/31001804320545/IDATs/597625150047/foo_bar_Red.idat",
)
def get_player_path(l, n):
pfl = set()
for i in l:
i = "/".join(i.split("/")[0:2])
if i not in pfl:
pfl.add(i)
if len(pfl) == n:
return pfl
if n > len(pfl):
print("not enough matches")
return
print(get_player_path(player_file_list, 2))
# {'2020-10-27/31001804320549', '2020-10-28/31001804320548'}
पायथन डेमो
आइए पहले अपने फ़ंक्शन का विश्लेषण करें:
- आपके लूप को इनपुट सूची की लंबाई में रैखिक समय (O (n)) लेना चाहिए, यह मानते हुए कि पथ की लंबाई अपेक्षाकृत "छोटी" संख्या से बंधी हुई है;
- छँटाई में O (n log (n)) तुलना होती है।
इस प्रकार जब सूची बड़ी हो जाती है तो छंटनी की प्रमुख लागत होती है। आप जितना चाहें उतना अपने लूप को माइक्रो-ऑप्टिमाइज़ कर सकते हैं, लेकिन जब तक आप अंत में उस तरह की छँटाई करते रहेंगे, तब तक आपके प्रयास से बड़ी सूचियों पर कोई फर्क नहीं पड़ेगा।
यदि आप सिर्फ पायथन स्क्रिप्ट लिख रहे हैं तो आपका दृष्टिकोण ठीक है। यदि आपको वास्तव में विशाल सूचियों के साथ सुगंध की आवश्यकता है, तो आप शायद किसी अन्य भाषा का उपयोग कर रहे हैं। फिर भी, यदि आप वास्तव में प्रदर्शन के बारे में परवाह करते हैं (या सिर्फ नया सामान सीखना है), तो आप निम्नलिखित तरीकों में से एक का प्रयास कर सकते हैं:
- स्ट्रिंग के लिए कुछ विशिष्ट के साथ सामान्य सॉर्टिंग एल्गोरिथ्म को बदलें; उदाहरण के लिए यहाँ देखें
- छँटाई की आवश्यकता को दूर करते हुए, एक ट्राइ का उपयोग करें ; यह सैद्धांतिक रूप से बेहतर हो सकता है लेकिन व्यवहार में शायद बदतर है।
पूर्णता के लिए, एक माइक्रो-ऑप्टिमाइज़ेशन के रूप में, यह मानते हुए कि तिथि में 10 वर्णों की निश्चित लंबाई है:
def get_player_path(player_file_list, total_players):
player_files_to_process = set()
for player_file in player_file_list:
end = player_file.find('/', 12) # <--- len(date) + len('/') + 1
file_path = player_file[:end] # <---
player_files_to_process.add(file_path)
if len(player_files_to_process) == total_players:
break
return sorted(player_files_to_process)
यदि आपकी उदाहरण सूची में आईडी की लंबाई भी निर्धारित है, तो आपको किसी विभाजन या खोजने की आवश्यकता नहीं है: बस
LENGTH = DATE_LENGTH + ID_LENGTH + 1 # 1 is for the slash between date and id
...
for player_file in player_file_list:
file_path = player_file[:LENGTH]
...
EDIT: LENGTH
इनिशियलाइज़ेशन तय किया, मैं 1 जोड़ना भूल गया था
तानाशाही का उपयोग करें ताकि आपकी सूची पहले से छँट जाने के बाद आपको उसे छाँटना न पड़े। यदि आपको अभी भी सॉर्ट करने की आवश्यकता है तो आप हमेशा रिटर्न स्टेटमेंट में सॉर्ट किए जा सकते हैं। आयात पुनः जोड़ें और अपने फ़ंक्शन को निम्नानुसार बदलें:
def get_player_path(player_file_list, total_players):
dct = {re.search('^\w+-\w+-\w+/\w+',pf).group(): 1 for pf in player_file_list}
return [k for i,k in enumerate(dct.keys()) if i < total_players]