অভিধানগুলিতে ক্রমটি কেন নির্বিচারে সেট হয়?


151

'স্বেচ্ছাসেবী' অর্ডার দিয়ে কীভাবে কোনও অভিধানে অজগর সেট করা যায় তা বুঝতে পারি না।

মানে, এটি একটি প্রোগ্রামিং ল্যাঙ্গুয়েজ তাই ভাষার প্রতিটি জিনিস অবশ্যই 100% নির্ধারিত, সঠিক? পাইথনকে অবশ্যই একধরণের অ্যালগরিদম থাকতে হবে যা সিদ্ধান্ত নেয় যে অভিধান বা সেটটি কোন অংশটি বেছে নেওয়া হয়েছে, প্রথম, দ্বিতীয় এবং আরও।

আমি কী মিস করছি?


1
সর্বশেষতম পাইপাই বিল্ড (পাইথন ২.7 এর জন্য ২.২) ডিফল্টরূপে অর্ডার করা অভিধান তৈরি করে
Veedrac

উত্তর:


236

দ্রষ্টব্য: এই উত্তরটি dictপাইথন ৩.6-তে পরিবর্তিত প্রকারটির প্রয়োগের আগে লেখা হয়েছিল । এই উত্তরে বাস্তবায়ন বিবরণ অধিকাংশই এখনও আবেদন করতে, কিন্তু কি অর্ডার তালিকা অভিধান আর হ্যাশ মান দ্বারা নির্ধারিত হয়। সেট প্রয়োগ অপরিবর্তিত রয়েছে।

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

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

স্লটগুলির উপরে সামগ্রীর লুপগুলি তালিকাভুক্ত করা হচ্ছে, এবং কীগুলি বর্তমানে সারণিতে যে ক্রমযুক্ত সেভাবে তালিকাভুক্ত রয়েছে।

উদাহরণস্বরূপ কীগুলি 'foo'এবং ধরুন এবং 'bar'টেবিলের আকারটি 8 স্লট ধরে নেওয়া যাক। পাইথন ২.7 hash('foo')-4177197833195190597, hash('bar')হয় 327024216814240868। মডিউল 8, এর অর্থ এই দুটি কী 3 এবং 4 এর স্লটে স্লটেড রয়েছে:

>>> hash('foo')
-4177197833195190597
>>> hash('foo') % 8
3
>>> hash('bar')
327024216814240868
>>> hash('bar') % 8
4

এটি তাদের তালিকার ক্রমকে অবহিত করে:

>>> {'bar': None, 'foo': None}
{'foo': None, 'bar': None}

3 এবং 4 ব্যতীত সমস্ত স্লট খালি রয়েছে, টেবিলের উপরে লুপ করে প্রথমে স্লট 3 তালিকা করে, তারপরে স্লট 4, সুতরাং 'foo'আগে তালিকাভুক্ত করা আছে 'bar'

barএবং baz, তবে হ্যাশ মানগুলি 8 টি পৃথক এবং এইভাবে একই একই স্লটে মানচিত্র করে 4:

>>> hash('bar')
327024216814240868
>>> hash('baz')
327024216814240876
>>> hash('bar') % 8
4
>>> hash('baz') % 8
4

তাদের অর্ডার এখন নির্ভর করে কোন কীটি প্রথমে স্লট করা হয়েছিল; দ্বিতীয় কীটি পরবর্তী স্লটে স্থানান্তরিত করতে হবে:

>>> {'baz': None, 'bar': None}
{'bar': None, 'baz': None}
>>> {'bar': None, 'baz': None}
{'baz': None, 'bar': None}

সারণির ক্রমটি এখানে পৃথক, কারণ এক বা অন্য কীটি প্রথমে স্লটেড ছিল।

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

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

অন্যান্য প্রয়োগগুলি অভিধানের জন্য আলাদা কাঠামো ব্যবহার করতে পারে, যতক্ষণ না তারা ডকুমেন্টেড পাইথন ইন্টারফেসটি তাদের জন্য সন্তুষ্ট করে তবে আমি বিশ্বাস করি যে এখনও পর্যন্ত সমস্ত বাস্তবায়ন হ্যাশ টেবিলের একটি প্রকরণ ব্যবহার করে।

সিপিথন ৩.6 একটি নতুন dict বাস্তবায়ন প্রবর্তন করে যা সন্নিবেশ ক্রম বজায় রাখে এবং এটি বুট করার জন্য দ্রুত এবং আরও মেমরির দক্ষ। একটি বৃহত স্পারস টেবিল রাখার পরিবর্তে যেখানে প্রতিটি সারি সঞ্চিত হ্যাশ মান, এবং কী এবং মান অবজেক্টের উল্লেখ করে, নতুন বাস্তবায়ন একটি ছোট হ্যাশ অ্যারে যুক্ত করে যা কেবল একটি পৃথক 'ঘন' সারণীতে সূচকগুলি উল্লেখ করে (এটি কেবলমাত্র সারি হিসাবে সারি থাকে) যেহেতু প্রকৃত কী-মান জোড় রয়েছে), এবং এটি ঘন টেবিল যা অন্তর্ভুক্ত থাকা আইটেমগুলিকে ক্রমানুসারে তালিকাবদ্ধ করে। আরও তথ্যের জন্য পাইথন-দেবকে প্রস্তাব দেখুন । দ্রষ্টব্য যে পাইথন ৩.6 এ এটি একটি বাস্তবায়ন বিশদ হিসাবে বিবেচিত হয়, পাইথন-দ্য ল্যাঙ্গুয়েজটি নির্দিষ্ট করে না যে অন্যান্য বাস্তবায়নের ক্রম ধরে রাখতে হবে। এটি পাইথন ৩.7-এ পরিবর্তিত হয়েছে, যেখানে এই বিবরণটি ভাষার স্পেসিফিকেশন হিসাবে উন্নত করা হয়েছিল ; পাইথন ৩.7 বা আরও নতুনের সাথে যথাযথভাবে সামঞ্জস্যপূর্ণ হওয়ার জন্য এটি অবশ্যই এই আদেশ-সংরক্ষণের আচরণটি অনুলিপি করতে হবে । এবং স্পষ্ট করে বলার জন্য: এই পরিবর্তনটি সেটগুলিতে প্রযোজ্য নয়, কারণ সেটগুলির ইতিমধ্যে একটি 'ছোট' হ্যাশ কাঠামো রয়েছে।

পাইথন 2.7 এবং নতুন একটি উপলব্ধ OrderedDictবর্গ , একটি উপশ্রেণী dictযে কী অর্ডার রেকর্ড করতে একটি অতিরিক্ত ডাটা স্ট্রাকচার যোগ করা হয়েছে। কিছু গতি এবং অতিরিক্ত মেমরির মূল্যে, এই শ্রেণিটি কী কী অর্ডার দিয়েছিল তা মনে রাখে; তালিকা কী, মান বা আইটেমগুলি তখন সেই ক্রমে তা করবে। আদেশটি দক্ষতার সাথে আপ-টু-ডেট রাখার জন্য এটি একটি অতিরিক্ত অভিধানে সজ্জিত দ্বিগুণ-লিঙ্কযুক্ত তালিকা ব্যবহার করে। রেমন্ড হেট্টিংগার পোস্টটি দেখুন ধারণাটি রূপরেখাOrderedDictঅবজেক্টের অন্যান্য সুবিধা রয়েছে যেমন রি-অরিড্রেসযোগ্য

যদি আপনি কোনও অর্ডারযুক্ত সেট চান, আপনি osetপ্যাকেজটি ইনস্টল করতে পারেন ; এটি পাইথন 2.5 এবং আরও উপরে কাজ করে।


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

1
@ ডেলানান: আমি অবাক হয়েছি আপনি যদি এখনও হ্যাশ এবং সমতা পরীক্ষা দিয়ে কোনও বিটি ট্রি ব্যবহার করতে পারেন .. তবে আমি অবশ্যই কোনও রায় দিচ্ছি না। :-)
মার্তিজান পিটারস

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

@ ডেলান: আমি সম্পূর্ণরূপে একমত; অন্যান্য বাস্তবায়ন বিকল্পের অনুমতি না দেওয়ার জন্য আমি বেশিরভাগই বেসড হতে চাই না।
মার্টিজন পিটারস

37

এটি নকল হিসাবে বন্ধ হওয়ার আগে পাইথন ৩.৪৪ সেটটির আরও প্রতিক্রিয়া ।


অন্যরা ঠিক বলেছেন: আদেশের উপর নির্ভর করবেন না। এমনকি একটি আছে ভান করবেন না।

এটি বলেছিল, আপনি নির্ভর করতে পারেন এমন একটি জিনিস রয়েছে:

list(myset) == list(myset)

যে, আদেশ স্থিতিশীল


কেন বোঝা অর্ডার রয়েছে তা বোঝার জন্য কয়েকটি জিনিস বোঝার প্রয়োজন:

  • পাইথন হ্যাশ সেট ব্যবহার করে ,

  • সিপিথনের হ্যাশ সেটটি কীভাবে মেমোরিতে সংরক্ষণ করা হয় এবং

  • কীভাবে সংখ্যাগুলি হ্যাশ হয়

উপর থেকে:

একটি হ্যাশ সেটটি সত্যই দ্রুত দেখার সময় সহ এলোমেলো ডেটা সংরক্ষণ করার একটি পদ্ধতি।

এটিতে একটি ব্যাকিং অ্যারে রয়েছে:

# A C array; items may be NULL,
# a pointer to an object, or a
# special dummy object
_ _ 4 _ _ 2 _ _ 6

আমরা বিশেষ ডামি অবজেক্টকে এড়িয়ে যাব, যা কেবলমাত্র মোকাবেলায় সরানো সহজতর করার জন্য বিদ্যমান, কারণ আমরা এই সেটগুলি থেকে সরব না।

সত্যিই দ্রুত সন্ধানের জন্য, আপনি কোনও বস্তু থেকে একটি হ্যাশ গণনা করতে কিছু জাদু করেন। একমাত্র নিয়ম যে দুটি বস্তু সমান যা একই হ্যাশযুক্ত। (তবে দুটি বস্তুর যদি একই হ্যাশ থাকে তবে তারা অসম হতে পারে))

তারপরে আপনি অ্যারে দৈর্ঘ্য অনুসারে মডিউল নিয়ে সূচকটি তৈরি করবেন:

hash(4) % len(storage) = index 2

এটি উপাদানগুলিতে অ্যাক্সেস করা সত্যিই দ্রুত করে তোলে।

হ্যাশগুলি কেবল গল্পের বেশিরভাগ অংশ hash(n) % len(storage)এবং hash(m) % len(storage)একই সংখ্যার ফলাফল হতে পারে। সেক্ষেত্রে বেশ কয়েকটি ভিন্ন কৌশল চেষ্টা করে বিরোধটি সমাধান করতে পারে। সিপিথন জটিল কাজগুলি করার আগে 9 বার "লিনিয়ার প্রোবিং" ব্যবহার করে, তাই অন্য কোথাও দেখার আগে এটি 9 টি পর্যন্ত স্লটের বাম দিকে তাক করবে।

সিপথনের হ্যাশ সেটগুলি এভাবে সংরক্ষণ করা হয়:

  • একটি হ্যাশ সেট 2/3 এর বেশি পূর্ণ হতে পারে না । যদি 20 টি উপাদান থাকে এবং ব্যাকিং অ্যারেটি 30 টি উপাদান দীর্ঘ হয় তবে ব্যাকিং স্টোরটি বৃহত্তর আকারে আকার পরিবর্তন করবে। এটি কারণ ছোট ছোট ব্যাকিং স্টোরগুলির সাথে আপনি প্রায়শই সংঘর্ষ পান এবং সংঘর্ষগুলি সমস্ত কিছু কমিয়ে দেয়।

  • ব্যাকিং স্টোরটি 4 টির আকারে আকার দেয়, 8 থেকে শুরু করে, বড় সেটগুলি (50 ক উপাদানগুলি) বাদে যা দুটি শক্তির আকার পরিবর্তন করে: (8, 32, 128, ...)।

সুতরাং আপনি যখন একটি অ্যারে তৈরি করবেন তখন ব্যাকিং স্টোরটি দৈর্ঘ্য 8 হয় it যখন এটি 5 টি পূর্ণ হয় এবং আপনি কোনও উপাদান যুক্ত করেন, এতে সংক্ষেপে 6 টি উপাদান থাকবে। 6 > ²⁄₃·8সুতরাং এটি একটি আকার পরিবর্তন করতে পারে এবং ব্যাকিং স্টোরটি 32 মাপের চতুর্দিকে।

পরিশেষে, hash(n)কেবল nসংখ্যার জন্য ফেরত দেয় (বাদে -1বিশেষ)।


সুতরাং, আসুন প্রথমটি দেখুন:

v_set = {88,11,1,33,21,3,7,55,37,8}

len(v_set)10, তাই সমস্ত আইটেম যুক্ত হওয়ার পরে ব্যাকিং স্টোরটি কমপক্ষে 15 (+1) হয় । 2 এর প্রাসঙ্গিক শক্তি 32. সুতরাং ব্যাকিং স্টোরটি হ'ল:

__ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __

আমাদের আছে

hash(88) % 32 = 24
hash(11) % 32 = 11
hash(1)  % 32 = 1
hash(33) % 32 = 1
hash(21) % 32 = 21
hash(3)  % 32 = 3
hash(7)  % 32 = 7
hash(55) % 32 = 23
hash(37) % 32 = 5
hash(8)  % 32 = 8

সুতরাং এই হিসাবে সন্নিবেশ:

__  1 __  3 __ 37 __  7  8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __
   33 ← Can't also be where 1 is;
        either 1 or 33 has to move

সুতরাং আমরা যেমন একটি আদেশ আশা করব

{[1 or 33], 3, 37, 7, 8, 11, 21, 55, 88}

1 বা 33 এর সাথে যা অন্য কোথাও শুরুতে নয়। এটি লিনিয়ার প্রোবিং ব্যবহার করবে, সুতরাং আমাদের হয় হয়:


__  1 33  3 __ 37 __  7  8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __

অথবা


__ 33  1  3 __ 37 __  7  8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __

আপনি সম্ভবত 33 টি বাস্তুচ্যুত হয়ে উঠবেন বলে আশা করতে পারেন কারণ 1 ইতিমধ্যে সেখানে ছিল, তবে সেটটি তৈরি হবার সাথে সাথে পুনরায় আকার দেওয়ার কারণে এটি আসলে ঘটেনি। প্রতিবার সেটটি পুনরায় তৈরি হয়ে গেলে, ইতিমধ্যে যুক্ত করা আইটেমগুলি কার্যকরভাবে পুনরায় সাজানো হয়।

এখন আপনি দেখতে পারেন কেন

{7,5,11,1,4,13,55,12,2,3,6,20,9,10}

ক্রম হতে পারে। এখানে 14 টি উপাদান রয়েছে, তাই ব্যাকিং স্টোরটি কমপক্ষে 21 + 1, যার অর্থ 32:

__ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __

প্রথম 13 স্লটে 1 থেকে 13 হ্যাশ। 20 স্লটে যায় 20।

__  1  2  3  4  5  6  7  8  9 10 11 12 13 __ __ __ __ __ __ 20 __ __ __ __ __ __ __ __ __ __ __

55 স্লটে যায় hash(55) % 32যা 23:

__  1  2  3  4  5  6  7  8  9 10 11 12 13 __ __ __ __ __ __ 20 __ __ 55 __ __ __ __ __ __ __ __

আমরা যদি এর পরিবর্তে 50 টি পছন্দ করি তবে আমরা আশা করব

__  1  2  3  4  5  6  7  8  9 10 11 12 13 __ __ __ __ 50 __ 20 __ __ __ __ __ __ __ __ __ __ __

এবং দেখুন এবং দেখুন:

{1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 20, 50}
#>>> {1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 50, 20}

pop জিনিসগুলির চেহারা দ্বারা বেশ সহজভাবে প্রয়োগ করা হয়: এটি তালিকাটিকে পিছনে ফেলে এবং প্রথমটিকে পপ করে।


এটি সমস্ত বাস্তবায়ন বিশদ।


17

"স্বেচ্ছাচারিতা" "অ-নির্ধারিত" এর মতো জিনিস নয়।

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

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


3
নোট করুন যে অভিধানের পুনরাবৃত্তির একটি অংশ ভালভাবে সংজ্ঞায়িত হয়েছে: একটি প্রদত্ত অভিধানের কী, মান বা আইটেমগুলির উপর পরীক্ষা করা প্রতিটি একই ক্রমে ঘটবে, যতক্ষণ না এর মধ্যে অভিধানে কোনও পরিবর্তন করা হয়নি changes তার মানে এটি d.items()মূলত অভিন্ন zip(d.keys(), d.values())। অভিধানে যদি কোনও আইটেম যুক্ত করা হয় তবে সমস্ত বেট বন্ধ রয়েছে। অর্ডারটি পুরোপুরি পরিবর্তিত হতে পারে (যদি হ্যাশ টেবিলটি পুনরায় আকার দেওয়ার দরকার হয়) তবে বেশিরভাগ সময় আপনি সন্ধানের কোনও স্বেচ্ছাসেবীর জায়গায় নতুন আইটেমটি সন্ধান করতে চান।
ব্ল্যাককিংহিট

6

এই প্রশ্নের অন্য উত্তরগুলি চমৎকার এবং ভাল লেখা are ওপি জিজ্ঞাসা করে "কীভাবে" যা আমি ব্যাখ্যা করি "তারা কীভাবে পালিয়ে যায়" বা "কেন"।

পাইথন ডকুমেন্টেশন বলছে ডিকশনারি অর্ডার করা হয় না কারণ পাইথন অভিধান বিমূর্ত ডেটা টাইপ এসোসিয়েটিভ অ্যারে প্রয়োগ করে । তারা যা বলল

বাইন্ডিংগুলি যে ক্রমে ফিরে আসে তা নির্বিচারে হতে পারে

অন্য কথায়, একটি কম্পিউটার বিজ্ঞানের শিক্ষার্থী ধরে নিতে পারে না যে কোনও এসোসিয়েটিভ অ্যারে অর্ডার করা হয়েছে। গণিতে সেটগুলির ক্ষেত্রেও এটি একই

কোনও সেটের উপাদানগুলি তালিকাভুক্ত হওয়া ক্রমটি অপ্রাসঙ্গিক

এবং কম্পিউটার বিজ্ঞান

একটি সেট একটি বিমূর্ত ডেটা টাইপ যা কোনও নির্দিষ্ট ক্রম ছাড়াই নির্দিষ্ট মান সংরক্ষণ করতে পারে

হ্যাশ টেবিল ব্যবহার করে অভিধান প্রয়োগ করা হ'ল একটি বাস্তবায়ন বিশদ যা এতে অর্ডারের সাথে সম্পর্কিত হিসাবে এসোসিয়েটিভ অ্যারেগুলির সমান বৈশিষ্ট্যগুলির মধ্যে আকর্ষণীয় in


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

5

পাইথন অভিধান সংরক্ষণের জন্য হ্যাশ টেবিল ব্যবহার করে, তাই অভিধান বা অন্যান্য পুনরাবৃত্ত বস্তুগুলিতে হ্যাশ টেবিল ব্যবহার করার কোনও আদেশ নেই।

কিন্তু একটি হ্যাশ বস্তু আইটেম সূচকের সংক্রান্ত, পাইথন কোড নিম্নলিখিত উপর ভিত্তি করে সূচকের গণনা মধ্যেhashtable.c :

key_hash = ht->hash_func(key);
index = key_hash & (ht->num_buckets - 1);

অতএব, যেমন পূর্ণসংখ্যার হ্যাশ মান পূর্ণসংখ্যা নিজেই * সূচক সংখ্যার উপর ভিত্তি করে করা হয় ( ht->num_buckets - 1একটি ধ্রুবক) যাতে সূচক নির্ণিত Bitwise-এবং মধ্যবর্তী (ht->num_buckets - 1)এবং নম্বর নিজেই * (প্রত্যাশায় আছি -1 যা এর হ্যাশ হয় -2 ), এবং তাদের হ্যাশ মান সহ অন্যান্য বস্তুর জন্য।

setহ্যাশ-টেবিল ব্যবহারের সাথে নিম্নলিখিত উদাহরণটি বিবেচনা করুন :

>>> set([0,1919,2000,3,45,33,333,5])
set([0, 33, 3, 5, 45, 333, 2000, 1919])

সংখ্যার জন্য 33আমাদের রয়েছে:

33 & (ht->num_buckets - 1) = 1

আসলে এটি:

'0b100001' & '0b111'= '0b1' # 1 the index of 33

এই ক্ষেত্রে নোট(ht->num_buckets - 1) হয় 8-1=7বা 0b111

এবং এর জন্য 1919:

'0b11101111111' & '0b111' = '0b111' # 7 the index of 1919

এবং এর জন্য 333:

'0b101001101' & '0b111' = '0b101' # 5 the index of 333

পাইথন হ্যাশ সম্পর্কে আরও তথ্যের জন্য পাইথনের উত্স কোড থেকে নিম্নলিখিত উদ্ধৃতিগুলি পড়তে ভাল :

সামনে প্রধান সূক্ষ্মতা: বেশিরভাগ হ্যাশ স্কিমগুলি এলোমেলো অনুকরণের অর্থে একটি "ভাল" হ্যাশ ফাংশন রাখার উপর নির্ভর করে। পাইথন এটি করে না: এর সর্বাধিক গুরুত্বপূর্ণ হ্যাশ ফাংশন (স্ট্রিং এবং ইনটগুলির জন্য) সাধারণ ক্ষেত্রে খুব নিয়মিত:

>>> map(hash, (0, 1, 2, 3))
  [0, 1, 2, 3]
>>> map(hash, ("namea", "nameb", "namec", "named"))
  [-1658398457, -1658398460, -1658398459, -1658398462]

এটি অগত্যা খারাপ নয়! বিপরীতে, আকারের একটি টেবিল 2 ** i, প্রাথমিক টেবিল সূচকটি অত্যন্ত দ্রুত হওয়ায় লো-অর্ডার i বিটগুলি গ্রহণ করা, এবং অন্তর্নির্মিত একটি নির্দিষ্ট পরিসীমা দ্বারা সূচিত ডিক্টগুলির জন্য মোটেই কোনও সংঘর্ষ নেই। কীগুলি যখন "পরপর" স্ট্রিং হয় তখন প্রায় একই রকম হয়। সুতরাং এটি সাধারণ ক্ষেত্রে তুলনায়-এলোমেলো আচরণ দেয় এবং এটি খুব আকাঙ্ক্ষিত।

ওটিওএইচ, যখন সংঘর্ষ হয়, হ্যাশ টেবিলের সংলগ্ন টুকরাগুলি পূরণ করার প্রবণতা একটি ভাল সংঘর্ষের সমাধানের কৌশলটিকে গুরুত্বপূর্ণ করে তোলে। হ্যাশ কোডের কেবলমাত্র শেষ আই বিটগুলি নেওয়াও দুর্বল: উদাহরণস্বরূপ, তালিকে [i << 16 for i in range(20000)]কীগুলির সেট হিসাবে বিবেচনা করুন । যেহেতু ইনটগুলি তাদের নিজস্ব হ্যাশ কোডগুলি হয় এবং এটি 2 ** 15 আকারের ডিকের সাথে ফিট করে, তাই প্রতিটি হ্যাশ কোডের শেষ 15 বিটগুলি সমস্ত 0 হয়: তারা সমস্ত একই টেবিল সূচকে মানচিত্র করে।

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


ক্লাসের জন্য হ্যাশ ফাংশন int:

class int:
    def __hash__(self):
        value = self
        if value == -1:
            value = -2
        return value


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