পাইথন: সন্ধানের টেবিলের জন্য তালিকা বনাম ডিক্ট


169

আমার প্রায় 10 মিলিয়ন মান রয়েছে যা আমার কোনও ধরণের লুক আপ টেবিলটি লাগানো দরকার, তাই আমি ভাবছিলাম যে কোন তালিকা বা ডিক আরও দক্ষ হবে ?

আমি জানি আপনি উভয়ের জন্য এই জাতীয় কিছু করতে পারেন:

if something in dict_of_stuff:
    pass

এবং

if something in list_of_stuff:
    pass

আমার ধারণা ডিকটি দ্রুত এবং আরও দক্ষ হবে efficient

আপনার সাহায্যের জন্য ধন্যবাদ.

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

সম্পাদনা 2
সন্ধানের জন্য দক্ষতা।

সম্পাদনা 3
মানটির সাথে জড়িত কোনও মান নেই ... তাই সেটটি আরও ভাল কি হতে পারে?


1
দক্ষতার দিক থেকে কী হবে? সন্নিবেশ? খুঁজে দেখো? স্মৃতিশক্তি? আপনি কি মূল্য বিশুদ্ধ এক্সটেনশন অনুসন্ধান করছেন, বা এর সাথে কোনও মেটাডেটা যুক্ত আছে?
truppo

পার্শ্ব নোট হিসাবে, আপনার নির্দিষ্ট সমস্যাটির জন্য 10 মিলিয়ন তালিকা বা ডিকের প্রয়োজন নেই তবে অনেক ছোট একটি।
sfotiadis

উত্তর:


222

গতি

তালিকাগুলিতে অনুসন্ধানগুলি হ'ল (এন), অভিধানগুলিতে অনুসন্ধানগুলি ডেটা স্ট্রাকচারের আইটেমের সংখ্যা বিবেচনা করে O যদি আপনার মানগুলি সংযুক্ত করার প্রয়োজন না হয় তবে সেটগুলি ব্যবহার করুন।

স্মৃতি

উভয় অভিধান এবং সেট হ্যাশিং ব্যবহার করে এবং তারা কেবল অবজেক্ট স্টোরেজের চেয়ে অনেক বেশি মেমরি ব্যবহার করে। এএম কুচলিং ইন বিউটিফুল কোড অনুসারে , প্রয়োগটি হ্যাশ 2/3 পূর্ণ রাখার চেষ্টা করে, যাতে আপনি বেশ কিছু স্মৃতি নষ্ট করতে পারেন।

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


6
হ্যাঁ, তবে বিষয়বস্তু কখনই পরিবর্তিত হয় না তা এটি এক-অফ অপারেশন। বাইনারি অনুসন্ধান হল (লগ এন)।
টর্স্টেন মেরেক

1
@ জন ফৌহী: ইনটগুলি হ্যাশ টেবিলে সংরক্ষণ করা হয় না, কেবলমাত্র পয়েন্টারগুলি থাকে, অর্থাত্ ইনটগুলির জন্য 40 এম রয়েছে (ভাল, যখন তাদের অনেকগুলি ছোট থাকে তবে সত্যই নয়) এবং হ্যাশ টেবিলের জন্য 60 এম। আমি সম্মতি জানাই যে এটি আজকাল কোনও সমস্যার খুব বেশি কিছু নয়, এখনও মনে রাখা ভাল while
টর্স্টেন মেরেক

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

3
এই টুইটটি আমাকে বিভ্রান্ত করে এই পৃষ্ঠাটি থেকে তালিকাটি হ'ল ও (1) এবং ডিক লুক হ'ল ও (এন), যা আপনি যা বলেছেন তার বিপরীত। আমি কি ভুল বুঝছি?
অস্থায়ী_ ব্যবহারকারী_নাম

3
@ অ্যারোভিস্টে আমি মনে করি আপনি সেই পৃষ্ঠায় থাকা তথ্যটি ভুলভাবে লিখেছেন। তালিকার অধীনে, আমি "x ইন এস" (অনুসন্ধান) এর জন্য ও (এন) দেখতে পাচ্ছি। এটি ও (1) গড় কেস হিসাবে সেট এবং ডিক লুকও দেখায়।
ডেনিস

45

একটি ডিক হ্যাশ টেবিল, তাই কীগুলি খুঁজে পাওয়া সত্যিই দ্রুত। সুতরাং ডিক এবং তালিকার মধ্যে ডিক দ্রুত হবে। তবে আপনার যদি সংযুক্ত হওয়ার মান না থাকে তবে সেটটি ব্যবহার করা আরও ভাল। এটি একটি হ্যাশ টেবিল, "টেবিল" অংশ ছাড়াই।


সম্পাদনা: আপনার নতুন প্রশ্নের জন্য, হ্যাঁ, একটি সেট আরও ভাল হবে। কেবলমাত্র 2 টি সেট তৈরি করুন, 1 টিতে সিকোয়েন্সগুলির জন্য একটি এবং অন্যটি সিকোয়েন্সগুলির 89 টিতে শেষ হয়েছিল sets সেটগুলি ব্যবহার করে আমি এই সমস্যাটি সফলভাবে সমাধান করেছি।



31

আমি কিছু বেঞ্চমার্কিং করেছি এবং এটি প্রমাণিত হয়েছে যে ডিক উভয় তালিকার চেয়ে দ্রুত এবং লিনাক্সের একটি আই 7 সিপিইউতে অজগর 2.7.3 চালিয়ে বড় ডেটা সেটগুলির জন্য সেট করেছে:

  • python -mtimeit -s 'd=range(10**7)' '5*10**6 in d'

    10 লুপ, 3 টির মধ্যে সেরা: লুপ প্রতি 64.2 মেসি

  • python -mtimeit -s 'd=dict.fromkeys(range(10**7))' '5*10**6 in d'

    10000000 লুপ, প্রতি লুপে 3: 0.0759 ইউএসসি সেরা

  • python -mtimeit -s 'from sets import Set; d=Set(range(10**7))' '5*10**6 in d'

    1000000 লুপস, 3 টির মধ্যে সেরা: 0.25 ইউজেক লুপ প্রতি

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


একেবারে বিপরীত হওয়া উচিত নয়? তালিকা: 10 * 64.2 * 1000 = 642000 ইউজেক, ডিক: 10000000 * 0.0759 = 759000 ইউএসিসি এবং সেট: 1000000 * 0.262 = 262000 ইউএসিসি ... সুতরাং সেটগুলি দ্রুততম, তালিকার পরে এবং ডিকের সাথে সর্বশেষে আপনার উদাহরণ হিসাবে রয়েছে। নাকি আমি কিছু মিস করছি?
andzep

1
... তবে এখানে আমার কাছে প্রশ্নটি হচ্ছে: এই সময়গুলি আসলে কী পরিমাপ করছে? প্রদত্ত তালিকার জন্য অ্যাক্সেসের সময়, ডিক বা সেট নয়, আরও অনেক কিছু, তালিকা তৈরি করতে সময় এবং লুপগুলি , ডিক্ট, সেট এবং শেষ পর্যন্ত একটি মান সন্ধান এবং অ্যাক্সেসের জন্য। সুতরাং, এই প্রশ্নটি কি আদৌ আছে? ... যদিও এটি আকর্ষণীয় ...
andzep

8
@ অ্যান্ডজেপ, আপনি ভুল হয়ে গেছেন, -sবিকল্পটি timeitপরিবেশ নির্ধারণ করা, অর্থাৎ এটি মোট সময় গণনা করে না। -sবিকল্প শুধুমাত্র একবার চালানো হয়। পাইথন ৩.৩-তে আমি এই ফলাফলগুলি পেয়েছি: জেন (রেঞ্জ) -> 0.229 ইউজেক, তালিকা -> 157 এমসিসি, ডিক -> 0.0806 ইউজেক, সেট -> 0.0807 ইউজেক। সেট এবং ডিক অভিনয় একই। ডিক্ট অবশ্য সেট (প্রাথমিক সময় 13.580s বনাম 11.803s) এর চেয়ে শুরু করতে খানিকটা বেশি সময় নেয়
স্লাবল্যাঙ্ক

1
কেন অন্তর্নির্মিত সেট ব্যবহার করবেন না? আমি আসলে সেটগুলির সাথে অনেক খারাপ ফলাফল পেয়েছি (বিল্টিন সেট () এর চেয়ে সেট ()
টমাস গিয়ট-সিওনেস্ট

2
@ থমাসগুইট-সিওনেস্ট সেটটি নির্মিত সেটটি পাইথন ২.৪-এ প্রবর্তিত হয়েছিল তাই আমি নিশ্চিত নই যে কেন আমি আমার প্রস্তাবিত সমাধানটিতে এটি ব্যবহার করিনি। python -mtimeit -s "d=set(range(10**7))" "5*10**6 in d"পাইথন ৩.০.০ (10000000 লুপগুলি, 3: 0.0608 লুপ প্রতি ব্যবহারের সেরা) ব্যবহার করে আমি ভাল পারফরম্যান্স পেয়েছি, যা ডিক বেঞ্চমার্কের মতো প্রায় একই তাই আপনার মন্তব্যের জন্য আপনাকে ধন্যবাদ।
EriF89 15

6

আপনি একটি ডিক চাই

পাইথনে (অরসোর্টড) তালিকাগুলির জন্য, "ইন" অপারেশনের জন্য ও (এন) সময় প্রয়োজন --- যখন আপনার প্রচুর পরিমাণে ডেটা থাকে তখন ভাল হয় না। অন্যদিকে, একটি ডিক হ্যাশ টেবিল, যাতে আপনি ও (1) দেখার সময় আশা করতে পারেন।

অন্যরা যেমন উল্লেখ করেছে, আপনি সম্ভবত কী / মান জোড়ার পরিবর্তে কীগুলি রেখে থাকেন তবে পরিবর্তে আপনি একটি সেট (একটি বিশেষ ধরণের ডিক) বেছে নিতে পারেন।

সম্পর্কিত:

  • পাইথন উইকি : পাইথন কনটেইনার কার্যক্রমের সময় জটিলতার তথ্য।
  • SO : পাইথন ধারক অপারেশন সময় এবং মেমরি জটিলতা

1
এমনকি বাছাই করা তালিকার জন্য, "ইন" হ'ল ও (এন)।

2
একটি লিঙ্কযুক্ত তালিকার জন্য, হ্যাঁ --- তবে পাইথনের "তালিকাগুলি" হ'ল বেশিরভাগ লোকেরা ভেক্টরকে ডাকে, যা বাছাই করার সময় ও (1) তে সূচিকৃত অ্যাক্সেস সরবরাহ করে এবং ও (লগ এন) এর সন্ধানের ক্রিয়াকলাপ সরবরাহ করে।
zweiterlinde

আপনি কি বলছেন যে inবাছাই করা তালিকার জন্য অপারেটর প্রয়োগ করা হয়েছে যখন কোনও অরসোর্টড (একটি এলোমেলো মানের সন্ধানের জন্য) প্রয়োগ করা হয়েছে তার চেয়ে ভাল সম্পাদন করে? (ভেক্টর হিসাবে বা কোনও লিঙ্ক-তালিকার নোড হিসাবে তারা অভ্যন্তরীণভাবে প্রয়োগ করা হয়েছে কিনা তা আমি প্রাসঙ্গিক বলে মনে করি না)
মার্টিনো

4

যদি ডেটা অনন্য সেট হয় () সর্বাধিক দক্ষ হবে তবে দুটি - ডিকের (যার জন্য স্বতন্ত্রতাও প্রয়োজন, ওফস :)


আমি যখন আমার উত্তর% পোস্ট করে দেখেছি তখন বুঝতে পেরেছি
সাইলেন্টগোস্ট

2
@ সাইলেন্টগোস্ট উত্তরটি যদি ভুল হয় তবে এটি মুছে ফেলছেন না কেন? upvotes জন্য খুব খারাপ, কিন্তু এটি ঘটে (ভাল, ঘটেছে )
জিন-

3

@ EriF89 কে দেখানোর জন্য পরীক্ষার নতুন সেট হিসাবে এখনও এই সমস্ত বছর পরে সঠিক:

$ python -m timeit -s "l={k:k for k in xrange(5000)}"    "[i for i in xrange(10000) if i in l]"
1000 loops, best of 3: 1.84 msec per loop
$ python -m timeit -s "l=[k for k in xrange(5000)]"    "[i for i in xrange(10000) if i in l]"
10 loops, best of 3: 573 msec per loop
$ python -m timeit -s "l=tuple([k for k in xrange(5000)])"    "[i for i in xrange(10000) if i in l]"
10 loops, best of 3: 587 msec per loop
$ python -m timeit -s "l=set([k for k in xrange(5000)])"    "[i for i in xrange(10000) if i in l]"
1000 loops, best of 3: 1.88 msec per loop

এখানে আমরা একটিকেও তুলনা করি tupleযা listsকিছু ব্যবহারের ক্ষেত্রে (এবং কম স্মৃতি ব্যবহারের চেয়ে) দ্রুত বলে পরিচিত । tupleসন্ধানের সারণির ক্ষেত্রে, সংযোজন আর ভাল নয়।

উভয় dictএবং setখুব ভাল অভিনয়। স্বতন্ত্রতা সম্পর্কে @ সাইলেন্টগোস্টের উত্তরের সাথে এটি একটি আকর্ষণীয় বিন্দুটি নিয়ে আসে: যদি কোনও ওপিতে কোনও ডাটা সেটে 10 এম মান থাকে এবং যদি সেগুলিতে সদৃশ থাকে তবে এটি অজানা হতে পারে তার উপাদানগুলির একটি সেট / ডিকটি সমান্তরালে রাখার জন্য উপযুক্ত হবে would প্রকৃত ডেটা সেট এবং সেই সেট / ডিকটিতে অস্তিত্বের জন্য পরীক্ষার সাথে। এটি সম্ভব 10 এম ডেটা পয়েন্টগুলির মধ্যে কেবল 10 টি অনন্য মান রয়েছে যা অনুসন্ধানের জন্য অনেক কম স্থান!

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

উদাহরণস্বরূপ, যদি অনুসন্ধান করা উত্স ডেটা তালিকাটি ছিল l=[1,2,3,1,2,1,4], এটি এই ডিকের পরিবর্তে অনুসন্ধান এবং মেমরি উভয়ের জন্যই অনুকূলিত করা যেতে পারে:

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> l=[1,2,3,1,2,1,4]
>>> for i, e in enumerate(l):
...     d[e].append(i)
>>> d
defaultdict(<class 'list'>, {1: [0, 3, 5], 2: [1, 4], 3: [2], 4: [6]})

এই আদেশের সাহায্যে, কেউ জানতে পারবেন:

  1. যদি মানটি মূল ডেটাসেটে থাকে (যেমন 2 in dপ্রত্যাবর্তন True)
  2. যেখানে মানটি মূল ডেটাসেটে ছিল (যেমন d[2]সূচকগুলির তালিকা প্রদান করে যেখানে মূল তথ্য তালিকায় ডেটা পাওয়া গেছে [1, 4]:)

আপনার শেষ অনুচ্ছেদের জন্য, এটি পড়ার তাৎপর্য বোধ করার পরে, আপনি যে আসল কোডটি ব্যাখ্যা করতে চাইছেন তা দেখতে খুব সুন্দর হবে (এবং সম্ভবত বুঝতে খুব সহজ) হবে।
কায়সার

0

আপনার আসলে টেবিলে ১০ মিলিয়ন মান সংরক্ষণ করার দরকার নেই, সুতরাং এটি কোনওভাবেই বড় বিষয় নয়।

ইঙ্গিত: স্কোয়ার অপারেশনের প্রথম যোগফলের পরে আপনার ফলাফলটি কতটা বড় হতে পারে সে সম্পর্কে ভাবুন। বৃহত্তম সম্ভাব্য ফলাফলটি 10 ​​মিলিয়নের চেয়ে অনেক ছোট হবে ...

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