পার্ল হ্যাশের চাবিগুলি দিয়ে পুনরাবৃত্তি করার সবচেয়ে নিরাপদ উপায় কী?


107

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

# Method 1
while (my ($key, $value) = each(%hash)) {
    # Something
}

# Method 2
foreach my $key (keys(%hash)) {
    # Something
}

উত্তর:


199

থাম্বের বিধিটি হ'ল আপনার প্রয়োজনের জন্য সবচেয়ে বেশি উপযুক্ত ফাংশনটি ব্যবহার করা।

আপনি যদি কীগুলি চান এবং মানগুলির কোনওটি পড়ার পরিকল্পনা না করেন, কীগুলি ব্যবহার করুন ():

foreach my $key (keys %hash) { ... }

আপনি যদি কেবল মানগুলি চান তবে মান () ব্যবহার করুন:

foreach my $val (values %hash) { ... }

যদি আপনার কী এবং মানগুলি প্রয়োজন হয় তবে প্রতিটি () ব্যবহার করুন:

keys %hash; # reset the internal iterator so a prior each() doesn't affect the loop
while(my($k, $v) = each %hash) { ... }

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

%h = (a => 1, b => 2);

foreach my $k (keys %h)
{
  $h{uc $k} = $h{$k} * 2;
}

প্রত্যাশিত ফলাফল হ্যাশ উত্পাদন:

(a => 1, A => 2, b => 2, B => 4)

তবে প্রতিটি () ব্যবহার করে একই জিনিসটি করা:

%h = (a => 1, b => 2);

keys %h;
while(my($k, $v) = each %h)
{
  $h{uc $k} = $h{$k} * 2; # BAD IDEA!
}

হার্ড-টু-প্রেডিক্ট পদ্ধতিতে ভুল ফলাফল উত্পন্ন করে। উদাহরণ স্বরূপ:

(a => 1, A => 2, b => 2, B => 8)

এটি তবে নিরাপদ:

keys %h;
while(my($k, $v) = each %h)
{
  if(...)
  {
    delete $h{$k}; # This is safe
  }
}

এই সবগুলি পার্ল ডকুমেন্টেশনে বর্ণিত হয়েছে:

% perldoc -f keys
% perldoc -f each

6
দয়া করে একটি শূন্য-প্রসঙ্গ কীগুলি% h যোগ করুন; প্রতিটি লুপ আগে পুনরুক্তি ব্যবহার করে নিরাপদে প্রদর্শিত হয়।
ysth

5
প্রত্যেকের সাথে আরও একটি সতর্কতা রয়েছে। পুনরুক্তিকারী হ্যাশের সাথে আবদ্ধ, প্রসঙ্গ নয়, যার অর্থ এটি পুনরায় প্রবেশকারী নয়। উদাহরণস্বরূপ, যদি আপনি কোনও হ্যাশ লুপ করেন এবং প্রিন্ট করে হ্যাশ পারল অভ্যন্তরীণভাবে পুনরাবৃত্তি করে পুনরায় সেট করে এই কোডটি অবিরাম লুপ করে তোলে: আমার% হ্যাশ = (a => 1, বি => 2, সি => 3,); যখন (আমার ($ কে, $ v) = প্রতিটি% হ্যাশ) {মুদ্রণ% হ্যাশ; Blo
ইউজারস /

28

ব্যবহার করার সময় আপনার একটি জিনিস সম্পর্কে সচেতন হওয়া উচিত eachএটি হ্যাশের আপনার হ্যাশটিতে "রাষ্ট্র" যুক্ত করার পার্শ্ব প্রতিক্রিয়া রয়েছে (হ্যাশটির "পরবর্তী" কী কী তা মনে রাখতে হবে)। উপরে পোস্ট করা স্নিপেটের মতো কোড ব্যবহার করার সময়, যা পুরো হ্যাশটিতে একসাথে পুনরাবৃত্তি হয়, এটি সাধারণত সমস্যা হয় না। যাইহোক, যদি আপনি সমস্যার খুঁজিয়া বাহির করা কঠিন মধ্যে চালানো হবে (আমি অভিজ্ঞতা থেকে কথা বলতে;), যখন ব্যবহার eachমত বিবৃতি দিয়ে একসঙ্গে lastবা returnথেকে প্রস্থান while ... eachলুপ আগে আপনি সমস্ত কী প্রক্রিয়াকরণ করেছি।

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

উদাহরণ:

my %hash = ( foo => 1, bar => 2, baz => 3, quux => 4 );

# find key 'baz'
while ( my ($k, $v) = each %hash ) {
    print "found key $k\n";
    last if $k eq 'baz'; # found it!
}

# later ...

print "the hash contains:\n";

# iterate over all keys:
while ( my ($k, $v) = each %hash ) {
    print "$k => $v\n";
}

এই মুদ্রণ:

found key bar
found key baz
the hash contains:
quux => 4
foo => 1

কীগুলি "বার" এবং বাজ "এর সাথে কী ঘটল? তারা এখনও সেখানে রয়েছে, তবে দ্বিতীয়টি eachশুরু হয় যেখানে প্রথমটি চলে যায় এবং এটি যখন হ্যাশের শেষের দিকে পৌঁছে যায় তখন থামে, তাই আমরা তাদের কখনই দ্বিতীয় লুপটিতে দেখি না।


22

যে জায়গাতেই eachআপনাকে সমস্যা দেখা দিতে পারে তা হ'ল এটি একটি সত্য, স্কোপবিহীন পুনরাবৃত্তিকারী। উদাহারন এর মাধ্যমে:

while ( my ($key,$val) = each %a_hash ) {
    print "$key => $val\n";
    last if $val; #exits loop when $val is true
}

# but "each" hasn't reset!!
while ( my ($key,$val) = each %a_hash ) {
    # continues where the last loop left off
    print "$key => $val\n";
}

আপনার যদি নিশ্চিত হওয়া দরকার যে এটি eachসমস্ত কী এবং মানগুলি পেয়েছে তবে আপনার অবশ্যই নিশ্চিত হওয়া উচিত যে আপনি ব্যবহার করছেন keysবা valuesপ্রথমে (যেমন পুনরুক্তি পুনরায় সেট করা হয়েছে)। প্রত্যেকের জন্য ডকুমেন্টেশন দেখুন ।


14

প্রতিটি সিনট্যাক্স ব্যবহার করে কীগুলির পুরো সেটটি একবারে উত্পন্ন হতে আটকাবে। আপনি লক্ষ লক্ষ সারি সহ একটি ডাটাবেসে একটি টাই-এড হ্যাশ ব্যবহার করছেন তবে এটি গুরুত্বপূর্ণ হতে পারে। আপনি একবারে কীগুলির পুরো তালিকাটি উত্পন্ন করতে এবং আপনার শারীরিক স্মৃতি থেকে বেরিয়ে আসতে চান না। এই ক্ষেত্রে প্রতিটি পুনরুক্তি হিসাবে কাজ করে যখন কীগুলি লুপটি শুরুর আগে পুরো অ্যারেটি তৈরি করে।

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

মেমোরি যদি সমস্যা না হয় তবে সাধারণত মানচিত্র বা কী দৃষ্টিকোণটি আরও উপস্থাপক এবং দৃষ্টান্ত পড়তে সহজ।


6

এই বিষয়ে কয়েকটি বিবিধ চিন্তাভাবনা:

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

2
"কীগুলির জন্য সত্য নয়" এর পরিবর্তে: এটি কীগুলির জন্য প্রযোজ্য নয় এবং কোনও মুছে ফেলা নিরাপদ। আপনি যে শব্দবন্ধগুলি ব্যবহার করছেন তা বোঝায় যে কীগুলি ব্যবহার করার সময় কোনও কিছুই মুছে ফেলা নিরাপদ নয়।
ysth

2
পুনরায়: "হ্যাশ পুনরাবৃত্তকারীগুলির কোনও সম্পর্কেই অনিরাপদ কিছুই নেই", অন্য বিপদটি ধরে নিচ্ছে যে প্রতিটি লুপ শুরু করার আগে পুনরুক্তিটি শুরুতে রয়েছে, যেমন অন্যরা উল্লেখ করেছেন।
ysth

3

আমি সবসময় পাশাপাশি পদ্ধতি 2 ব্যবহার করি। প্রতিটি ব্যবহারের একমাত্র সুবিধা হ'ল আপনি যদি হ্যাশ প্রবেশের মানটি কেবল (পুনরায় বরাদ্দ করার চেয়ে) পড়ছেন তবে আপনি ক্রমাগত হ্যাশটিকে ডি-রেফারেন্সিং করছেন না।


3

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

যা যা বলেছিল, আমি প্রায় সবসময় কী () ব্যবহার করি কারণ আমার কাছে সাধারণত হ্যাশের মাধ্যমে কীটির মানটি অ্যাক্সেস করার জন্য এটি আরও বেশি স্ব নথিভুক্ত হয়। আমি মাঝেমধ্যে মানগুলি ব্যবহার করি (যখন মানটি একটি বৃহত কাঠামোর রেফারেন্স হয় এবং হ্যাশের চাবিটি কাঠামোতে ইতিমধ্যে সঞ্চিত থাকে, যার বিন্দুতে কীটি অপ্রয়োজনীয় এবং আমার এটির প্রয়োজন হয় না)। আমি মনে করি আমি পার্ল প্রোগ্রামিংয়ের 10 বছরে প্রতিটি () 2 বার ব্যবহার করেছি এবং এটি সম্ভবত দু'বারই ভুল পছন্দ ছিল =)


2

আমি সাধারণত ব্যবহার করি keysএবং আমি শেষবার কখন ব্যবহার করেছিলাম বা পড়ার কথা ভাবতে পারি না each

mapলুপটিতে আপনি কী করছেন তার উপর নির্ভর করে ভুলে যাবেন না !

map { print "$_ => $hash{$_}\n" } keys %hash;

6
আপনি যদি ফেরতের মান না চান তবে মানচিত্রটি ব্যবহার করবেন না
কো-ডস

-1

আমি বলি:

  1. বেশিরভাগ লোকের পক্ষে পড়া / বোঝার জন্য যা সহজ, তা ব্যবহার করুন (তাই কীগুলি সাধারণত, আমি যুক্তি দিয়ে থাকি)
  2. আপনি যা যা নিয়মিত স্থির করেন তা পুরো কোড বেসটি ব্যবহার করুন।

এটি 2 বড় সুবিধা দেয়:

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

আমি মনে করি না যে এটির জন্য কীগুলি ব্যবহার করা আরও ব্যয়বহুল, সুতরাং আপনার কোডে একই জিনিসটির জন্য দুটি পৃথক কনস্ট্রাক্টের প্রয়োজন নেই।


1
keysমেমরির ব্যবহার বাড়ার সাথে সাথে hash-size * avg-key-size। প্রদত্ত যে কী আকার ওনলি মেমোরি দ্বারা সীমাবদ্ধ (যেমন তাদের "তাদের" ফণা অধীন সংশ্লিষ্ট মান মত শুধু অ্যারে উপাদানের দর্শিত থাকবে), কিছু পরিস্থিতিতে এটা হতে পারে নিষেধাজ্ঞামূলকভাবে আরো উভয় মেমোরি ব্যবহার এবং সময় কপি করতে নিয়ে যাওয়া ব্যয়বহুল।
অ্যাড্রিয়ান গন্টার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.