ওভাররাইডের জন্য সেরা অনুশীলনগুলি হল একাল: এবং হ্যাশ


267

আপনি কীভাবে সঠিকভাবে isEqual:উদ্দেশ্য-সিটিতে ওভাররাইড করবেন ? "ধরা" দেখে মনে হচ্ছে যে দুটি বস্তু সমান হলে ( isEqual:পদ্ধতি অনুসারে নির্ধারিত ), তাদের অবশ্যই হ্যাশ মান একই হবে।

অন্তর্দর্শন বিভাগে কোকো প্রাথমিক ধারনা গাইড কিভাবে ওভাররাইড করতে উপর একটি উদাহরণ আছে isEqual:, নিম্নরূপ কপি, নামে একজন বর্গ জন্য MyWidget:

- (BOOL)isEqual:(id)other {
    if (other == self)
        return YES;
    if (!other || ![other isKindOfClass:[self class]])
        return NO;
    return [self isEqualToWidget:other];
}

- (BOOL)isEqualToWidget:(MyWidget *)aWidget {
    if (self == aWidget)
        return YES;
    if (![(id)[self name] isEqual:[aWidget name]])
        return NO;
    if (![[self data] isEqualToData:[aWidget data]])
        return NO;
    return YES;
}

এটি পয়েন্টার সমতা, তারপরে শ্রেণীর সাম্যতা পরীক্ষা করে এবং শেষ পর্যন্ত ব্যবহার করে অবজেক্টগুলির সাথে তুলনা করে isEqualToWidget:, যা কেবলমাত্র nameএবং dataবৈশিষ্ট্যগুলি পরীক্ষা করে । উদাহরণটি যা দেখায় না তা হ'ল কীভাবে ওভাররাইড করা যায় hash

আসুন ধরে নেওয়া যাক এমন অন্যান্য বৈশিষ্ট্য রয়েছে যা সমতাকে প্রভাবিত করে না, বলুন agehashপদ্ধতিটি কী এমন ওভাররাইড করা উচিত নয় যে কেবল nameএবং হ্যাশকে dataপ্রভাবিত করে? এবং যদি তা হয় তবে আপনি কীভাবে তা করবেন? শুধু হ্যাশ যোগ nameএবং data? উদাহরণ স্বরূপ:

- (NSUInteger)hash {
    NSUInteger hash = 0;
    hash += [[self name] hash];
    hash += [[self data] hash];
    return hash;
}

তা কি যথেষ্ট? এর চেয়ে ভাল কৌশল আছে কি? আপনার যদি আদিম থাকে, তবে কি int? NSNumberতাদের হ্যাশ পেতে তাদের রূপান্তর করবেন ? বা স্ট্রাক্টের মতো NSRect?

( ব্রেন ফার্ট : মূলত এগুলি একসাথে "বিটওয়াইস ওআর" লিখেছিলেন |=ant


2
if (![other isKindOfClass:[self class]])- এর প্রযুক্তিগত অর্থ হল সাম্যতা পরিবর্তিত হবে না। আই এ = বি এর অর্থ বি = এ নয় (উদাহরণস্বরূপ যদি অন্যের সাবক্লাস হয়)
রবার্ট

নথিপত্র লিংক মৃত, এখন সংরক্ষণ করা হচ্ছেনা অন্তর্দর্শন
jedwidz

উত্তর:


111

শুরু করা

 NSUInteger prime = 31;
 NSUInteger result = 1;

তারপরে প্রতিটি আদিম জন্য আপনি করেন

 result = prime * result + var

বস্তুর জন্য আপনি শূন্যের জন্য 0 ব্যবহার করেন এবং অন্যথায় তাদের হ্যাশকোড।

 result = prime * result + [var hash];

বুলিয়ানগুলির জন্য আপনি দুটি পৃথক মান ব্যবহার করেন

 result = prime * result + ((var)?1231:1237);

ব্যাখ্যা এবং গুণাবলী

এটি টিচার্টের কাজ নয়, এবং মন্তব্যগুলি আরও ব্যাখ্যা চেয়েছিল, সুতরাং আমি বিশ্বাস করি যে এন্ট্রিবিউশনের জন্য সম্পাদনাটি ন্যায্য।

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

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


9
1231: 1237 কোথা থেকে এসেছে? আমি এটি জাভার বুলিয়ান.হ্যাশকোডেও দেখতে পাচ্ছি। এটা কি যাদু?
ডেভিড লিওনার্ড

17
এটি হ্যাশিং অ্যালগরিদমের প্রকৃতি যে সেখানে সংঘর্ষ হবে। সুতরাং আমি আপনার বক্তব্য দেখতে পাচ্ছি না, পল।
tcurdt

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

6
1 ম সমস্যা - (অন্তর্নিহিত) ছোট এবং ওভারফ্লো করা সহজ, এনএসইউইন্টেজারটি ব্যবহার করুন। ২ য় সমস্যা - আপনি যদি প্রতিটি ভেরিয়েবল হ্যাশ দ্বারা ফলাফলকে গুণতে থাকেন তবে আপনার ফলাফল উপচে পড়বে। যেমন। [এনএসএসটিং হ্যাশ] বড় মান তৈরি করে। আপনার যদি 5+ ভেরিয়েবল থাকে তবে এই অ্যালগরিদম দিয়ে উপচে পড়া সহজ। এটি একই হ্যাশটিতে ম্যাপিংয়ের ফলাফল হিসাবে আসবে যা খারাপ। আমার প্রতিক্রিয়া দেখুন: স্ট্যাকওভারফ্লো.com
পল সোল্ট

10
@ পলসোল্ট - হ্যাশ তৈরিতে ওভারফ্লো কোনও সমস্যা নয়, সংঘর্ষ। তবে ওভারফ্লো অবিচ্ছিন্নভাবে সংঘর্ষের সম্ভাবনা বেশি নয় এবং ওভারফ্লো সম্পর্কে আপনার বক্তব্য একই হ্যাশটিতে ম্যাপ করার জন্য সমস্ত কিছু ঘটায় তা কেবল ভুল simply
ডগডাব্লু

81

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

অন্যদিকে, যদি 2 টি উদাহরণ সমান না হয় তবে তাদের একই হ্যাশ থাকতে পারে বা নাও থাকতে পারে - তারা না দিলে সবচেয়ে ভাল is এটি হ্যাশ টেবিলের ও (1) অনুসন্ধান এবং একটি ও (এন) অনুসন্ধানের মধ্যে পার্থক্য - যদি আপনার সমস্ত হ্যাশ সংঘর্ষে দেখা যায় যে আপনার টেবিলটি অনুসন্ধানের তালিকাগুলির চেয়ে আরও ভাল কিছু নয় no

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

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


4
+1 দুর্দান্ত উত্তর, আরও উত্সাহের দাবিদার, বিশেষত যেহেতু তিনি আসলে "সেরা অনুশীলন" এবং কেন একটি ভাল (অনন্য) হ্যাশ গুরুত্বপূর্ণ তার পিছনে তত্ত্ব সম্পর্কে কথা বলেছেন talks
কুইন টেলর

30

সমালোচনামূলক বৈশিষ্ট্যের হ্যাশ মানগুলির উপর একটি সাধারণ এক্সওআর সময়টির 99% যথেষ্ট।

উদাহরণ স্বরূপ:

- (NSUInteger)hash
{
    return [self.name hash] ^ [self.data hash];
}

ম্যাট থম্পসনের http://nshipster.com/equality/ এ সমাধান পাওয়া গেছে (যা তার পোস্টে এই প্রশ্নটিও উল্লেখ করেছে!)


1
এই উত্তরের সমস্যাটি হ'ল এটি আদৌ আদি মূল্যবোধ বিবেচনা করে না। এবং আদিম মানগুলি হ্যাশিংয়ের জন্যও গুরুত্বপূর্ণ হতে পারে।
ভিভ করুন

@ লাইভ এই সমস্যাগুলির বেশিরভাগটি সুইফটে সমাধান করা হয় তবে এগুলি সাধারণত আদিম হওয়ার কারণে এই ধরণেরগুলি সাধারণত তাদের নিজস্ব হ্যাশ উপস্থাপন করে।
ইয়ারিভ নিসিম

1
আপনি যখন সুইফ্টের পক্ষে ঠিক আছেন, তবুও অনেকগুলি প্রজেক্ট অবজেক্ট দিয়ে লেখা রয়েছে। কারণ আপনার উত্তরটি আপজকের জন্য উত্সর্গীকৃত এটি কমপক্ষে একটি উল্লেখযোগ্য।
11:48

একসাথে জোরিং হ্যাশ মানগুলি খারাপ পরামর্শ, এটি অনেকগুলি হ্যাশের সংঘর্ষের দিকে পরিচালিত করে। পরিবর্তে, একটি মৌলিক সংখ্যার সাথে গুণ করুন এবং তারপরে অন্যান্য উত্তরগুলির হিসাবে যুক্ত করুন।
ফিশিনিয়ার

27

আমার isEqual:এবং hashপদ্ধতিগুলি একটি ধরা দিয়ে প্রয়োগ করার জন্য আমার প্রয়োজনীয় সমস্ত সরবরাহ করতে এই থ্রেডটি চূড়ান্ত সহায়ক বলে মনে করেছি । isEqual:উদাহরণ কোডে অবজেক্ট উদাহরণের ভেরিয়েবলগুলি পরীক্ষা করার সময় :

if (![(id)[self name] isEqual:[aWidget name]])
    return NO;

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

if (![nil isEqual: nil])
    return NO;

এবং যেহেতু শূন্য যে কোনও পদ্ধতিতে সাড়া দেবে, এটি পুরোপুরি আইনী তবে but

[nil isEqual: nil]

রিটার্ন শূন্য করে , যা কোনও হয় না , সুতরাং যখন বস্তু এবং পরীক্ষিত উভয়ের একটি শূন্য বস্তু থাকত তখন তারা সমান না হিসাবে বিবেচিত হত ( যেমন , isEqual:কোনও ফেরত দেয় না )।

এই সাধারণ ফিক্সটি ছিল যদি বিবৃতিটি এতে পরিবর্তন করে:

if ([self name] != [aWidget name] && ![(id)[self name] isEqual:[aWidget name]])
    return NO;

এইভাবে, যদি তাদের ঠিকানাগুলি একই হয় তবে পদ্ধতি কলটি এড়িয়ে যায় না তারা উভয় শূন্য বা উভয় একই বস্তুর দিকে নির্দেশ করছে তবে যদি শূন্য না হয় বা তারা বিভিন্ন বস্তুর দিকে নির্দেশ করে তবে তুলনাকারীকে যথাযথভাবে বলা হয়।

আমি আশা করি এটি কারও কয়েক মিনিটের মাথা চুলকানোকে বাঁচায়।


20

হ্যাশ ফাংশনটি এমন একটি আধা-স্বতন্ত্র মান তৈরি করতে হবে যা অন্য কোনও বস্তুর হ্যাশ মানের সাথে সংঘর্ষ বা মিলে যাওয়ার সম্ভাবনা নেই।

এখানে সম্পূর্ণ হ্যাশ ফাংশন রয়েছে যা আপনার শ্রেণীর উদাহরণ ভেরিয়েবলের সাথে মানিয়ে নেওয়া যায়। এটি 64/32 বিট অ্যাপ্লিকেশনগুলিতে সামঞ্জস্যের পরিবর্তে এনএসইউইন্টিজারের ব্যবহার করে।

ফলাফলটি যদি বিভিন্ন অবজেক্টের জন্য 0 হয়ে যায় তবে আপনি হ্যাশগুলির সংঘর্ষের ঝুঁকিটি চালান। হ্যাশ ফাংশনের উপর নির্ভরশীল কিছু সংগ্রহের ক্লাসের সাথে কাজ করার সময় কলাইডিং হ্যাশগুলির ফলাফল অপ্রত্যাশিত প্রোগ্রামের আচরণে ঘটতে পারে। ব্যবহারের আগে আপনার হ্যাশ ফাংশনটি পরীক্ষা করার বিষয়টি নিশ্চিত করুন।

-(NSUInteger)hash {
    NSUInteger result = 1;
    NSUInteger prime = 31;
    NSUInteger yesPrime = 1231;
    NSUInteger noPrime = 1237;

    // Add any object that already has a hash function (NSString)
    result = prime * result + [self.myObject hash];

    // Add primitive variables (int)
    result = prime * result + self.primitiveVariable; 

    // Boolean values (BOOL)
    result = prime * result + (self.isSelected?yesPrime:noPrime);

    return result;
}

3
এখানে একটি গোছা: আমি বিন্দু বাক্য গঠন এড়াতে পছন্দ করি, তাই আমি আপনার BOOL বিবৃতিটিকে (যেমন) রূপান্তরিত করেছি result = prime * result + [self isSelected] ? yesPrime : noPrime;। আমি তখন এটি result(উদাহরণস্বরূপ) এ সেট করে 1231দেখলাম, আমি ধরে নিয়েছি ?অপারেটর অগ্রাধিকার গ্রহণের কারণে । আমি বন্ধনী যুক্ত করে বিষয়টি ঠিক করেছি:result = prime * result + ([self isSelected] ? yesPrime : noPrime);
অ্যাশলে

12

সহজ তবে অদক্ষ উপায় হ'ল -hashপ্রতিটি উদাহরণের জন্য একই মান ফেরত । অন্যথায় হ্যাঁ, আপনাকে কেবলমাত্র বস্তুগুলির উপর ভিত্তি করে হ্যাশ প্রয়োগ করতে হবে যা সাম্যাকে প্রভাবিত করে। যদি আপনি লক্ষ তুলনা ব্যবহার করেন তবে এটি জটিল -isEqual:(উদাহরণস্বরূপ কেস-সংবেদনশীল স্ট্রিং তুলনা)। ইনটসের জন্য, আপনি সাধারণত ইনট নিজেই ব্যবহার করতে পারেন, যদি না আপনি এনএসএন নাম্বারের সাথে তুলনা করছেন।

| = ব্যবহার করবেন না, যদিও এটি পরিপূর্ণ হবে। পরিবর্তে ^ = ব্যবহার করুন।

এলোমেলো মজাদার ঘটনা: [[NSNumber numberWithInt:0] isEqual:[NSNumber numberWithBool:NO]]কিন্তু [[NSNumber numberWithInt:0] hash] != [[NSNumber numberWithBool:NO] hash]। (রাইডার: // 4538282, 05-মে-2006-এর পরে খোলা)


1
আপনি ঠিক ঠিক | আসলেই এর অর্থ হয়নি। :) + = এবং ^ = মোটামুটি সমতুল্য। আপনি ডাবল এবং ফ্লোটের মতো অ-পূর্ণসংখ্যার আদিম কীভাবে পরিচালনা করবেন?
ডেভ ড্রিবিন

এলোমেলো মজাদার ঘটনা: এটি স্নো চিতাবাঘে পরীক্ষা করুন ... ;-)
কুইন টেলর

তিনি হ্যাশের সাথে ক্ষেত্রগুলি একত্রিত করার জন্য OR এর পরিবর্তে XOR ব্যবহার সম্পর্কে সঠিক using তবে, প্রতিটি বস্তুর জন্য একই-হ্যাশ মানটি ফেরত দেওয়ার পরামর্শটি ব্যবহার করবেন না - যদিও এটি সহজ, এটি বস্তুর হ্যাশ ব্যবহার করে এমন কোনও কিছুর কার্যকারিতা মারাত্মকভাবে হ্রাস করতে পারে । হ্যাশ নেই আছে যে বস্তু সমান নয় জন্য স্বতন্ত্র হতে, কিন্তু যদি আপনি যে অর্জন করতে পারেন, এটা মত কিছুই নেই।
কুইন টেলর 14

উন্মুক্ত রাডার বাগ রিপোর্ট বন্ধ রয়েছে। openradar.me/4538282 এর অর্থ কী?
জেজেডি

জেজেডি, কুইন ইঙ্গিত করার সাথে সাথে ম্যাক ওএস এক্স 10.6 এ বাগটি ঠিক করা হয়েছিল। (দ্রষ্টব্য যে মন্তব্যটি দুই বছরের পুরানো।)
জেনস আইটন

9

মনে রাখবেন যে আপনার যখন isEqualসত্য হয় তখন কেবল হ্যাশ সরবরাহ করতে হবে । যখন isEqualমিথ্যা হয়, সম্ভবত হ্যাশটি অসম হতে হবে না uma অত: পর:

হ্যাশ সরল রাখুন। কোনও সদস্য (বা কয়েকটি সদস্য) ভেরিয়েবল চয়ন করুন যা সবচেয়ে স্বতন্ত্র।

উদাহরণস্বরূপ, সিএলপ্লেসমার্কের জন্য কেবল নামটিই যথেষ্ট। হ্যাঁ ঠিক একই নামের সাথে 2 বা 3 টি আলাদা আলাদা সিএলপ্লেসমার্ক রয়েছে তবে সেগুলি বিরল। যে হ্যাশ ব্যবহার করুন।

@interface CLPlacemark (equal)
- (BOOL)isEqual:(CLPlacemark*)other;
@end

@implementation CLPlacemark (equal)

...

-(NSUInteger) hash
{
    return self.name.hash;
}


@end

নোটিশ আমি শহর, দেশ ইত্যাদি নির্দিষ্ট করে বিরক্ত করি না নামটি যথেষ্ট। সম্ভবত নাম এবং CLLocation।

হ্যাশ সমানভাবে বিতরণ করা উচিত। সুতরাং আপনি ক্যারেট using (জোর সাইন) ব্যবহার করে বেশ কয়েকটি সদস্যকে পরিবর্তনশীল একত্রিত করতে পারেন

সুতরাং এটি কিছু মত

hash = self.member1.hash ^ self.member2.hash ^ self.member3.hash

এইভাবে হ্যাশটি সমানভাবে বিতরণ করা হবে।

Hash must be O(1), and not O(n)

সুতরাং অ্যারে করতে কি?

আবার, সরল। আপনাকে অ্যারের সমস্ত সদস্যকে হ্যাশ করতে হবে না। প্রথম উপাদান, শেষ উপাদান, গণনা, সম্ভবত কিছু মাঝারি উপাদান হ্যাশ করা যথেষ্ট এবং এটি।


XORing হ্যাশ মানগুলি এমনকি বিতরণ দেয় না।
ফিশিনিয়ার

7

হোল্ড করুন, অবশ্যই এটি করার একটি আরও সহজ উপায় হ'ল প্রথমে ওভাররাইড করা - (NSString )descriptionএবং আপনার অবজেক্টের স্থিতির একটি স্ট্রিং প্রতিনিধিত্ব সরবরাহ করা (আপনাকে অবশ্যই এই স্ট্রিংয়ে আপনার অবজেক্টের পুরো রাজ্যের প্রতিনিধিত্ব করতে হবে)।

তারপরে, কেবল নিম্নলিখিতটির বাস্তবায়ন সরবরাহ করুন hash:

- (NSUInteger)hash {
    return [[self description] hash];
}

এটি এই নীতির উপর ভিত্তি করে তৈরি করা হয়েছে যে "যদি দুটি স্ট্রিং অবজেক্ট সমান হয় (আইকুয়ালটোস্ট্রিং: পদ্ধতি দ্বারা নির্ধারিত হয়) তবে তাদের অবশ্যই হ্যাশ মান থাকতে হবে।"

উত্স: এনএসএসআরটিং ক্লাস রেফারেন্স


1
এটি ধরে নিয়েছে যে বর্ণনা পদ্ধতিটি অনন্য হবে। বর্ণনার হ্যাশ ব্যবহার করে একটি নির্ভরতা তৈরি হয়, এটি সুস্পষ্ট নাও হতে পারে এবং সংঘর্ষের উচ্চতর ঝুঁকি রয়েছে।
পল সোল্ট

1
+1 আপভোটেড। এটা একটি অসাধারণ চিন্তা. যদি আপনি ভয় পান যে বিবরণগুলি সংঘর্ষের কারণ হয়ে থাকে, তবে আপনি এটিকে ওভাররাইড করতে পারেন।
ব্যবহারকারী4951

ধন্যবাদ জিম, আমি অস্বীকার করব না যে এটি কিছুটা হ্যাক, তবে এটি যে কোনও ক্ষেত্রেই আমি ভাবতে পারি তা কার্যকর হবে - এবং আমি যেমন বলেছিলাম যে আপনি যে ওভাররাইড করে তা প্রদান করে description, আমি দেখতে পাচ্ছি না কেন এটি নিম্নমানের উচ্চতর ভোট দেওয়া সমাধানগুলির কোনও। সবচেয়ে গাণিতিকভাবে মার্জিত সমাধান নাও হতে পারে তবে কৌশলটি করা উচিত। যেমনটি ব্রায়ান বি লিখেছেন (এই সময়ে সর্বাধিক উত্সাহিত উত্তর): "আমি নতুন হ্যাশ অ্যালগরিদম তৈরি এড়াতে চেষ্টা করি" - সম্মত! - আমি শুধু ! hashNSString
জোনাথন এলিস

উত্সাহিত কারণ এটি একটি ঝরঝরে ধারণা। আমি যদিও এটি ব্যবহার করতে যাচ্ছি না কারণ আমি অতিরিক্ত এনএসএসস্ট্রিং বরাদ্দকে ভয় করি।
কারওয়াগ

1
এটি একটি জেনেরিক সমাধান নয় কারণ বেশিরভাগ ক্লাসের descriptionজন্য পয়েন্টার ঠিকানা অন্তর্ভুক্ত রয়েছে। সুতরাং এটি একই শ্রেণীর দুটি পৃথক দৃষ্টান্ত তৈরি করে যা বিভিন্ন হ্যাশের সাথে সমান, যা দুটি সমান বস্তুর একই হ্যাশ রয়েছে এমন মৌলিক ধারণাটিকে লঙ্ঘন করে!
ডায়োগো টি

5

সমান এবং হ্যাশ চুক্তিগুলি জাভা বিশ্বে ভালভাবে নির্দিষ্ট এবং পুঙ্খানুপুঙ্খভাবে গবেষণা করা হয়েছে (@ মাইপার্ডির উত্তর দেখুন), তবে একই একই বিবেচনাগুলি উদ্দেশ্য-সি-তে প্রযোজ্য উচিত।

Eclipse জাভাতে এই পদ্ধতিগুলি উত্পন্ন করার একটি নির্ভরযোগ্য কাজ করে, সুতরাং এখানে একটি Elpipse উদাহরণ হ'ল Objective-C- র হাতে পোর্ট করা হয়েছে:

- (BOOL)isEqual:(id)object {
    if (self == object)
        return true;
    if ([self class] != [object class])
        return false;
    MyWidget *other = (MyWidget *)object;
    if (_name == nil) {
        if (other->_name != nil)
            return false;
    }
    else if (![_name isEqual:other->_name])
        return false;
    if (_data == nil) {
        if (other->_data != nil)
            return false;
    }
    else if (![_data isEqual:other->_data])
        return false;
    return true;
}

- (NSUInteger)hash {
    const NSUInteger prime = 31;
    NSUInteger result = 1;
    result = prime * result + [_name hash];
    result = prime * result + [_data hash];
    return result;
}

এবং একটি সাবক্লাসের জন্য YourWidgetযা একটি সম্পত্তি যুক্ত করে serialNo:

- (BOOL)isEqual:(id)object {
    if (self == object)
        return true;
    if (![super isEqual:object])
        return false;
    if ([self class] != [object class])
        return false;
    YourWidget *other = (YourWidget *)object;
    if (_serialNo == nil) {
        if (other->_serialNo != nil)
            return false;
    }
    else if (![_serialNo isEqual:other->_serialNo])
        return false;
    return true;
}

- (NSUInteger)hash {
    const NSUInteger prime = 31;
    NSUInteger result = [super hash];
    result = prime * result + [_serialNo hash];
    return result;
}

এই প্রয়োগটি isEqual:অ্যাপল থেকে নমুনায় কিছু সাবক্লাসিং ক্ষতিগুলি এড়িয়ে চলে :

  • অ্যাপলের ক্লাস টেস্ট other isKindOfClass:[self class]দুটি পৃথক সাবক্লাসের অসমমিতি MyWidget। সমতাটি প্রতিসম হওয়া দরকার: a = b যদি এবং কেবলমাত্র b = a। পরীক্ষায় পরিবর্তন করে সহজেই এটি ঠিক করা যেতে পারে other isKindOfClass:[MyWidget class], তবে সমস্ত MyWidgetসাবক্লাস পারস্পরিক তুলনামূলক হবে।
  • isKindOfClass:সাবক্লাস পরীক্ষাটি ব্যবহার করে সাবক্লাসগুলি isEqual:একটি পরিশোধিত সাম্যতা পরীক্ষা দিয়ে ওভাররাইড করা থেকে বিরত থাকে। এটি কারণ সাম্যতাটি ট্রানজিটিভ হওয়া দরকার: যদি a = b এবং a = c হয় তবে b = c। যদি একটি MyWidgetউদাহরণ দুটি উদাহরণের সাথে সমান তুলনা করে YourWidget, তবে সেই YourWidgetদৃষ্টান্তগুলি অবশ্যই একে অপরের সাথে সমান তুলনা করতে হবে, এমনকি তার serialNoভিন্নতা থাকলেও ।

দ্বিতীয় ইস্যুটি ঠিক একই শ্রেণীর অন্তর্ভুক্ত হলে অবজেক্টগুলি সমান হিসাবে বিবেচনা করে স্থির করা যেতে পারে, সুতরাং এখানে [self class] != [object class]পরীক্ষা test সাধারণ অ্যাপ্লিকেশন ক্লাসের জন্য , এটি সর্বোত্তম পন্থা বলে মনে হয়।

যাইহোক, isKindOfClass:পরীক্ষাগুলি পছন্দসই এমন ক্ষেত্রে অবশ্যই রয়েছে । এটি অ্যাপ্লিকেশন ক্লাসের চেয়ে ফ্রেমওয়ার্ক ক্লাসগুলির বেশি নির্দিষ্ট । উদাহরণস্বরূপ, / পার্থক্য নির্বিশেষে এবং ক্লাস ক্লাস্টারে কোন প্রাইভেট ক্লাস জড়িত তা নির্বিশেষে যে কোনওটিকে একই অন্তর্নিহিত অক্ষর ক্রমের সাথে NSStringঅন্য যে কোনও সাথে সমান তুলনা করা উচিত ।NSStringNSStringNSMutableStringNSString

এই ধরনের ক্ষেত্রে, isEqual:ভাল-সংজ্ঞায়িত, ভাল-ডকুমেন্টেড আচরণ থাকা উচিত এবং এটি পরিষ্কার করা উচিত যে সাবক্লাসগুলি এটিকে ওভাররাইড করতে পারে না। জাভাতে সমান এবং হ্যাশকোড পদ্ধতিগুলি পতাকাঙ্কিত করে 'নো ওভাররাইড' বিধিনিষেধ প্রয়োগ করা যেতে পারে final, তবে উদ্দেশ্য-সি এর সমতুল্য নেই।


@ অ্যাডাবর এটি আমার শেষ দুটি অনুচ্ছেদে আচ্ছাদিত। এটি কেন্দ্রিয় নয় MyWidgetযেমন বোঝা যায় যে ক্লাস ক্লাস্টার না হয়ে।
jedwidz

5

এটি সরাসরি আপনার প্রশ্নের উত্তর দেয় না (তবে মোটামুটি) তবে আমি হ্যাশগুলি তৈরি করার আগে মর্মুরহ্যাশ ব্যবহার করেছি: মুরমারহশ

অনুমান করুন কেন আমার ব্যাখ্যা করা উচিত: বচসা দ্রুত রক্তাক্ত ...


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

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

5

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



4

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


আমি একজন কোকো / অবজেক্টিভ সি নবাগত এবং এই উত্তর এবং লিঙ্কটি আমাকে নীচের লাইনে আরও উন্নত সমস্ত জিনিস কাটাতে সহায়তা করেছে - আমাকে হ্যাশ সম্পর্কে চিন্তা করার দরকার নেই - কেবল ইস্কুল: পদ্ধতি প্রয়োগ করে। ধন্যবাদ!
জন গ্যালাগার

@ সিপেরির লিঙ্কটি মিস করবেন না। Equality vs Identityকার্ল ক্রাফ্টের নিবন্ধটি সত্যিই ভাল।
জেজেডি

6
@ জন: আমি মনে করি আপনার নিবন্ধটি পুনরায় পড়া উচিত। এটি খুব স্পষ্টভাবে বলেছে যে "সমান উদাহরণগুলির সমান হ্যাশ মান থাকতে হবে।" আপনি যদি ওভাররাইড করেন তবে isEqual:আপনাকে অবশ্যই ওভাররাইড করতে হবে hash
স্টিভ ম্যাডসেন

3

কুইন একেবারেই ভুল যে এখানে বচসা হ্যাশের রেফারেন্সটি অকেজো। কুইন ঠিক আছে যে আপনি হ্যাশিং এর পিছনের তত্ত্বটি বুঝতে চান। বচসা সেই তত্ত্বকে প্রচুর পরিমাণে বাস্তবায়িত করে। এই প্রয়োগটি কীভাবে এই বিশেষ প্রয়োগে প্রয়োগ করা যায় তা নির্ধারণ করার জন্য মূল্যবান।

এখানে কিছু মূল বিষয়:

Tcurdt এর উদাহরণ ফাংশনটি বোঝায় যে '31' একটি ভাল গুণক কারণ এটি প্রধান। একজনকে দেখাতে হবে যে প্রধান হওয়া একটি প্রয়োজনীয় এবং পর্যাপ্ত শর্ত। আসলে 31 (এবং 7) সম্ভবত বিশেষ ভাল প্রাইমস নয় কারণ 31 == -1% 32. প্রায় অর্ধেক বিট সেট এবং অর্ধেক বিট পরিষ্কার সহ একটি বিজোড় গুণক আরও ভাল হতে পারে। (বচসা হ্যাশ গুণের ধ্রুবকের সেই সম্পত্তি রয়েছে))

এই ধরণের হ্যাশ ফাংশনটি আরও শক্তিশালী হবে যদি, গুণনের পরে, ফলাফলের মানটি একটি শিফট এবং জোওরের মাধ্যমে সামঞ্জস্য করা হয়। গুণটি নিবন্ধের উচ্চ প্রান্তে প্রচুর বিট ইন্টারেক্টের ফলাফল এবং নিবন্ধের নীচের প্রান্তে কম মিথস্ক্রিয়া ফলাফলগুলি তৈরি করে। শিফট এবং xor নিবন্ধকের নীচের প্রান্তে ইন্টারঅ্যাকশনগুলি বাড়িয়ে তোলে।

প্রায় অর্ধেক বিট শূন্য এবং প্রায় অর্ধেক বিট একটি মান হিসাবে প্রাথমিক ফলাফল নির্ধারণ করাও কার্যকর হতে পারে।

যে উপাদানগুলিতে একত্রিত হয় সে সম্পর্কে সতর্কতা অবলম্বন করা কার্যকর হতে পারে। একটি সম্ভবত বুলিয়ান এবং অন্যান্য উপাদানগুলিতে প্রক্রিয়া করা উচিত যেখানে মানগুলি দৃ strongly়ভাবে বিতরণ করা হয় না।

গণনার শেষে বেশ কয়েকটি অতিরিক্ত বিট স্ক্র্যাম্বলিং পর্যায়ে যুক্ত করা কার্যকর হতে পারে।

এই অ্যাপ্লিকেশনটির জন্য বচসা হ্যাশ আসলে দ্রুত কিনা তা একটি উন্মুক্ত প্রশ্ন। মুরমার হ্যাশ প্রতিটি ইনপুট শব্দের বিটকে প্রিমিক্স করে। একাধিক ইনপুট শব্দের সমান্তরালে প্রক্রিয়া করা যায় যা একাধিক-ইস্যু পাইপলাইনযুক্ত সিপাসকে সহায়তা করে।


3

সম্পত্তির নাম পাওয়ার জন্য @ অ্যাসকার-গোমেজের জবাবের সাথে @ ট্যকর্ড্টের উত্তরটির সংমিশ্রণ , আমরা ইস্কুল এবং হ্যাশ উভয়ের জন্য একটি সহজ ড্রপ-ইন সমাধান তৈরি করতে পারি:

NSArray *PropertyNamesFromObject(id object)
{
    unsigned int propertyCount = 0;
    objc_property_t * properties = class_copyPropertyList([object class], &propertyCount);
    NSMutableArray *propertyNames = [NSMutableArray arrayWithCapacity:propertyCount];

    for (unsigned int i = 0; i < propertyCount; ++i) {
        objc_property_t property = properties[i];
        const char * name = property_getName(property);
        NSString *propertyName = [NSString stringWithUTF8String:name];
        [propertyNames addObject:propertyName];
    }
    free(properties);
    return propertyNames;
}

BOOL IsEqualObjects(id object1, id object2)
{
    if (object1 == object2)
        return YES;
    if (!object1 || ![object2 isKindOfClass:[object1 class]])
        return NO;

    NSArray *propertyNames = PropertyNamesFromObject(object1);
    for (NSString *propertyName in propertyNames) {
        if (([object1 valueForKey:propertyName] != [object2 valueForKey:propertyName])
            && (![[object1 valueForKey:propertyName] isEqual:[object2 valueForKey:propertyName]])) return NO;
    }

    return YES;
}

NSUInteger MagicHash(id object)
{
    NSUInteger prime = 31;
    NSUInteger result = 1;

    NSArray *propertyNames = PropertyNamesFromObject(object);

    for (NSString *propertyName in propertyNames) {
        id value = [object valueForKey:propertyName];
        result = prime * result + [value hash];
    }

    return result;
}

এখন, আপনার কাস্টম শ্রেণিতে আপনি সহজেই প্রয়োগ করতে পারবেন isEqual:এবং hash:

- (NSUInteger)hash
{
    return MagicHash(self);
}

- (BOOL)isEqual:(id)other
{
    return IsEqualObjects(self, other);
}

2

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

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

এটি আমার কাছে সম্পূর্ণ তৃণমূলের মতো বলে মনে হচ্ছে এটি সম্ভাব্য কার্যকরভাবে হ্যাশ লুক্কুটগুলি আরও কম দক্ষ করে তোলে, তবে আমি মনে করি সাবধানতার দিক থেকে ভুল করে ডকুমেন্টেশন যা বলে তা অনুসরণ করা ভাল।


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

1

দুঃখিত আমি যদি এখানে একটি সম্পূর্ণ বফিন শোনার ঝুঁকি নিয়ে থাকি তবে ... ... 'সেরা অনুশীলনগুলি' অনুসরণ করতে আপনার অবশ্যই কোনও সমান পদ্ধতি নির্দিষ্ট করা উচিত নয় যা আপনার টার্গেট অবজেক্টের মালিকানাধীন সমস্ত ডেটা বিবেচনা করবে না, যেমন যাই হোক না কেন সমতা বাস্তবায়নের সময় ডেটা আপনার সামগ্রীতে একত্রিত হয়, বনাম এর সহযোগী, বিবেচনায় নেওয়া উচিত। আপনি যদি তুলনা না করে অ্যাকাউন্টে 'বয়স' বলতে চান না, তবে আপনার তুলনামূলক লিখতে হবে এবং এটি আপনার তুলনা সম্পাদনের জন্য ব্যবহার করা উচিত ইসুয়াল: এর পরিবর্তে।

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

তবে, যদিও এটি হ্যাশিং সম্পর্কে দুর্দান্ত প্রশ্নোত্তর, আপনার সাধারণত হ্যাশিং পদ্ধতিটি নতুনভাবে সংজ্ঞায়িত করার প্রয়োজন হয় না, এর পরিবর্তে আপনার সম্ভবত একটি অ্যাডহক তুলক সংজ্ঞায়িত করা উচিত।

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