पर्ल हैश की चाबियों के माध्यम से फिर से शुरू करने का सबसे सुरक्षित तरीका क्या है?

अगर मेरे पास एक पर्ल हैश (कुंजी, मूल्य) जोड़े के समूह के साथ है, तो सभी चाबियों के माध्यम से पुनरावृत्ति करने की पसंदीदा विधि क्या है? मैंने सुना है कि प्रत्येक का उपयोग किसी भी तरह से अनपेक्षित दुष्प्रभाव हो सकता है। तो, क्या यह सच है, और यह निम्न दो तरीकों में से एक है, या क्या कोई बेहतर तरीका है?

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

# Method 2
foreach my $key (keys(%hash)) {
    # Something
}
0
जोड़ा संपादित
विचारों: 2

8 उत्तर

अंगूठे का नियम आपकी आवश्यकताओं के लिए उपयुक्त फ़ंक्शन का उपयोग करना है।

यदि आप केवल चाबियाँ चाहते हैं और किसी भी मान को पढ़ा कभी भी योजना बनाने की योजना नहीं बनाते हैं, तो कुंजी() का उपयोग करें:

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
  }
}

यह सब perl दस्तावेज़ीकरण में वर्णित है:

% perldoc -f keys
% perldoc -f each
0
जोड़ा
प्रत्येक के साथ एक और चेतावनी है। इटेटरेटर हैश से बंधे हैं, संदर्भ नहीं, जिसका अर्थ है कि यह पुनः प्रवेश नहीं है। उदाहरण के लिए यदि आप हैश पर लूप करते हैं, और हैश पर्ल प्रिंट करते हैं तो आंतरिक रूप से इटरेटर को रीसेट कर देगा, इस कोड लूप को अंतहीन बना देगा: मेरा% हैश = (ए => 1, बी => 2, सी => 3,); जबकि (मेरा ($ के, $ v) = प्रत्येक% हैश) {प्रिंट% हैश; } blogs.perl.org/ पर और पढ़ें उपयोगकर्ताओं / rurban / 2014/04 /-न-उपयोग-each.html
जोड़ा लेखक Rawler, स्रोत
कृपया एक शून्य-संदर्भ कुंजी% एच जोड़ें; प्रत्येक लूप को इटरेटर का उपयोग करके सुरक्षित रूप से दिखाने के लिए।
जोड़ा लेखक ysth, स्रोत

इस विषय पर कुछ विविध विचार:

  1. किसी भी हैश इटेटर स्वयं के बारे में कुछ भी असुरक्षित नहीं है। असुरक्षित क्या है जब आप इसके ऊपर फिर से चल रहे हैंश की चाबियाँ संशोधित कर रहे हैं। (यह मानों को संशोधित करने के लिए पूरी तरह से सुरक्षित है।) एकमात्र संभावित दुष्प्रभाव मैं सोच सकता हूं कि मान उपनाम देता है जिसका अर्थ है कि उन्हें संशोधित करना हैश की सामग्री को संशोधित करेगा। यह डिज़ाइन द्वारा है लेकिन हो सकता है कि आप कुछ परिस्थितियों में जो भी चाहते हैं।
  2. जॉन के स्वीकृत उत्तर </ए> एक अपवाद के साथ अच्छा है: दस्तावेज़ीकरण स्पष्ट है कि हैश पर पुनरावृत्ति करते समय कुंजी जोड़ने के लिए सुरक्षित नहीं है। यह कुछ डेटा सेट के लिए काम कर सकता है लेकिन हैश ऑर्डर के आधार पर दूसरों के लिए असफल हो जाएगा।
  3. जैसा कि पहले से ही उल्लेख किया गया है, प्रत्येक द्वारा लौटाई गई अंतिम कुंजी को हटाना सुरक्षित है। यह कुंजी के लिए नहीं सत्य है प्रत्येक एक पुनरावर्तक है जबकि keys एक सूची देता है।
0
जोड़ा
पुनः "कुंजी के लिए सही नहीं", बल्कि: यह कुंजी पर लागू नहीं है और कोई भी डिलीट सुरक्षित है। आपके द्वारा उपयोग किए जाने वाले वाक्यांश का तात्पर्य है कि कुंजी का उपयोग करते समय कुछ भी हटाना सुरक्षित नहीं होता है।
जोड़ा लेखक ysth, स्रोत
पुन: "किसी भी हैश इटरेटर्स के बारे में कुछ भी असुरक्षित नहीं है", दूसरा खतरा यह मान रहा है कि प्रत्येक लूप शुरू करने से पहले शुरुआत में इटेटरेटर शुरू हो रहा है, जैसा कि दूसरों का उल्लेख है।
जोड़ा लेखक ysth, स्रोत

मैं आमतौर पर कुंजी का उपयोग करता हूं और मैं पिछली बार प्रत्येक के उपयोग को पढ़ने या पढ़ने के बारे में नहीं सोच सकता।

लूप में आप जो कर रहे हैं उसके आधार पर map के बारे में न भूलें!

map { print "$_ => $hash{$_}\n" } keys %hash;
0
जोड़ा
जब तक आप वापसी मूल्य नहीं चाहते हैं तब तक मानचित्र का उपयोग न करें
जोड़ा लेखक ko-dos, स्रोत

प्रत्येक का उपयोग करते समय आपको अवगत होना चाहिए कि यह है आपके हैश में "राज्य" जोड़ने का दुष्प्रभाव (हैश को याद रखना है "अगली" कुंजी क्या है)। ऊपर पोस्ट किए गए स्निपेट जैसे कोड का उपयोग करते समय, जो एक ही बार में पूरे हैश पर फिर से शुरू होता है, यह आम तौर पर नहीं होता है मुसीबत। हालांकि, आप समस्याओं को ट्रैक करने के लिए कड़ी मेहनत करेंगे (मैं बोलता हूं अनुभव;), जब प्रत्येक का उपयोग कथन के साथ करते हैं अंतिम या वापसी जबकि ... प्रत्येक लूप से पहले बाहर निकलने के लिए सभी चाबियाँ संसाधित की है।

इस मामले में, हैश याद रखेगा कि कौन सी कुंजी पहले से ही लौट आई है, और जब आप अगली बार प्रत्येक का उपयोग करते हैं (शायद कुल असंबद्ध टुकड़े में कोड), यह इस स्थिति में जारी रहेगा।

उदाहरण:

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

कुंजी "बार" और बाज़ के साथ क्या हुआ "? वे अभी भी वहां हैं, लेकिन दूसरा <�कोड> प्रत्येक शुरू होता है जहां पहला छोड़ा जाता है, और जब यह हैश के अंत तक पहुंच जाता है, तो हम उन्हें दूसरे लूप में कभी नहीं देखते हैं।

0
जोड़ा

मैं हमेशा विधि 2 का भी उपयोग करता हूं। प्रत्येक का उपयोग करने का एकमात्र लाभ यह है कि यदि आप हैश प्रविष्टि के मान को पढ़ रहे हैं (फिर से असाइन करने के बजाए), तो आप लगातार हैश को संदर्भित नहीं कर रहे हैं।

0
जोड़ा

मैं इस से काट सकता हूं लेकिन मुझे लगता है कि यह व्यक्तिगत वरीयता है। मुझे प्रत्येक() को कुंजी() या मानों() से अलग होने के लिए दस्तावेज़ों में कोई संदर्भ नहीं मिल रहा है (स्पष्ट "वे अलग-अलग चीजें वापस करते हैं" उत्तर के अलावा। वास्तव में दस्तावेज़ों में एक ही इटरेटर का उपयोग होता है और वे सभी उनमें से प्रतियों की बजाय वास्तविक सूची मान वापस करें, और किसी भी कॉल का उपयोग करके इसे फिर से चालू करते समय हैश को संशोधित करना बुरा है।

जो कुछ भी कहा, मैं लगभग हमेशा चाबियाँ() का उपयोग करता हूं क्योंकि मेरे लिए आमतौर पर हैश के माध्यम से कुंजी के मूल्य तक पहुंचने के लिए यह अधिक स्वयं दस्तावेज़िंग होता है। मैं कभी-कभी मानों() का उपयोग करता हूं जब मान एक बड़ी संरचना का संदर्भ होता है और हैश की कुंजी संरचना में पहले से ही संग्रहीत होती है, जिस बिंदु पर कुंजी अनावश्यक है और मुझे इसकी आवश्यकता नहीं है। मुझे लगता है कि मैंने पर्ल प्रोग्रामिंग के 10 वर्षों में प्रत्येक() 2 बार उपयोग किया है और शायद यह दोनों बार गलत विकल्प था =)

0
जोड़ा

वह स्थान जहां प्रत्येक आपको समस्याएं पैदा कर सकता है वह यह है कि यह एक वास्तविक, गैर-स्कोप्ड इटरेटर है। उदाहरण के माध्यम से:

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";
}

यदि आपको यह सुनिश्चित करने की आवश्यकता है कि प्रत्येक सभी कुंजी और मान प्राप्त करता है, तो आपको यह सुनिश्चित करना होगा कि आप keys या values ​​ पहले उपयोग करें (जैसा कि इटरेटर रीसेट करता है)। प्रत्येक के लिए दस्तावेज़ देखें।

0
जोड़ा
सावधान नहीं होने पर यह $$ में काट सकता है
जोड़ा लेखक sdkks, स्रोत

मैं woudl कहते हैं:

  1. अधिकांश लोगों के लिए पढ़ने / समझने के लिए जो भी आसान है (इसलिए कुंजी, आमतौर पर, मैं बहस करता हूं)
  2. जो भी आप पूरे कोड बेस के माध्यम से लगातार निर्णय लेते हैं उसका प्रयोग करें।

यह 2 प्रमुख फायदे देता है:

  1. "सामान्य" कोड को स्पॉट करना आसान है ताकि आप फ़ंक्शंस / मेथियोड में फिर से कारक बना सकें।
  2. भविष्य के डेवलपर्स को बनाए रखना आसान है।

मुझे नहीं लगता कि प्रत्येक पर चाबियों का उपयोग करना अधिक महंगा है, इसलिए आपके कोड में एक ही चीज़ के लिए दो अलग-अलग संरचनाओं की आवश्यकता नहीं है।

0
जोड़ा
कुंजी स्मृति उपयोग हैश-आकार * औसत-कुंजी-आकार से बढ़ता है। यह देखते हुए कि मुख्य आकार केवल स्मृति द्वारा ही सीमित है (क्योंकि वे केवल "तत्व" जैसे हूड के समान तत्व हैं), कुछ परिस्थितियों में यह निषिद्ध स्मृति उपयोग और समय दोनों में अधिक महंगा हो सकता है प्रतिलिपि बनाने के लिए लिया गया।
जोड़ा लेखक Adrian Günter, स्रोत