2012-06-06 17 views
15

मैं each उपयोग कर रहा हूँ एक पर्ल हैश के माध्यम से पुनरावृति करने के लिए:क्या मैं अपने "प्रत्येक" इटरेटर को रीसेट किए बिना हैश कॉपी कर सकता हूं?

while (my ($key,$val) = each %hash) { 
    ... 
} 

फिर कुछ दिलचस्प होता है और मैं हैश प्रिंट आउट करना चाहते हैं। पहले तो मुझे कुछ पर विचार करें:

while (my ($key,$val) = each %hash) { 
    if (something_interesting_happens()) { 
     foreach my $k (keys %hash) { print "$k => $hash{$k}\n" } 
    } 
} 

लेकिन वह काम नहीं करेगा, क्योंकि हर कोई जानता है कि एक हैश पर keys (या values) बुला आंतरिक each के लिए इस्तेमाल किया इटरेटर रीसेट करता है, और हम एक अनंत लूप मिल सकता है। उदाहरण के लिए, ये स्क्रिप्ट हमेशा के लिए चलेगी:

perl -e '%a=(foo=>1); while(each %a){keys %a}' 
perl -e '%a=(foo=>1); while(each %a){values %a}' 

कोई समस्या नहीं, मैंने सोचा। मैं हैश की एक प्रति बना सकता हूं, और प्रतिलिपि मुद्रित कर सकता हूं।

if (something_interesting_happens()) { 
     %hash2 = %hash; 
     foreach my $k (keys %hash2) { print "$k => $hash2{$k}\n" } 
    } 

लेकिन वह काम नहीं करता है, या तो। यह each इटरेटर को भी रीसेट करता है। वास्तव में, किसी सूची संदर्भ में %hash का कोई भी उपयोग अपने each इटरेटर को रीसेट करने लगता है। तो ये हमेशा के लिए दौड़ते हैं:

perl -e '%a=(foo=>1); while(each %a){%b = %a}' 
perl -e '%a=(foo=>1); while(each %a){@b = %a}' 
perl -e '%a=(foo=>1); while(each %a){print %a}' 

क्या यह कहीं भी दस्तावेज है? यह समझ में आता है कि एक हैश की सामग्री को रिटर्न स्टैक पर धक्का देने के लिए पर्ल को एक ही आंतरिक इटरेटर का उपयोग करने की आवश्यकता हो सकती है, लेकिन मैं हैश कार्यान्वयन की भी कल्पना कर सकता हूं जिसे ऐसा करने की आवश्यकता नहीं थी।

अधिक महत्वपूर्ण बात यह है कि क्या मैं चाहता हूं कि ऐसा करने का कोई तरीका है? each इटरेटर को रीसेट किए बिना हैश के सभी तत्वों को प्राप्त करने के लिए?


यह भी पता चलता है कि आप एक each यात्रा के अंदर एक हैश डिबग नहीं कर सकते हैं, या तो। पर डिबगर चलाने पर विचार करें:

%a = (foo => 123, bar => 456); 
while (($k,$v) = each %a) { 
    $DB::single = 1; 
    $o .= "$k,$v;"; 
} 
print $o; 

बस हैश जहां डिबगर बंद हो जाता है (जैसे कि, p %a या x %a टाइपिंग) का निरीक्षण करके, आप कार्यक्रम के उत्पादन में बदल जाएगा।


अद्यतन: मैं इस समस्या का एक सामान्य समाधान के रूप में Hash::SafeKeys अपलोड की गई। मुझे सही दिशा में इंगित करने के लिए @gpojd धन्यवाद और एक सुझाव के लिए @cjm जिसने समाधान को अधिक सरल बना दिया।

+0

हाल ही में एक ही समस्या का सामना किया। पता चला है कि हैश :: सेफकीज़ बहुत धीमी है और हैश आकार पर निर्भर करता है, और हैश :: स्टोर्ड इटरेटर + डिफ़ॉल्ट कुंजी बहुत बेहतर प्रदर्शन करती है। –

+0

@AlexandrEvstigneev - धन्यवाद, यह बहुत दिलचस्प है। मैं 'हैश :: सेफकीज़' – mob

उत्तर

9

क्या आपने इसे कॉपी करने के लिए Storable'sdclone को आजमाया है?

use Storable qw(dclone); 
my %hash_copy = %{ dclone(\%hash) }; 
+3

'perl -MStorable = dclone -e '% a = (foo => 1) में कुछ अपडेट करूँगा; जबकि (प्रत्येक% ए) {dclone \% a}' 'अनंत नहीं है लूप जब मैं कोशिश करता हूँ। – cjm

+0

ऐसा लगता है कि काम करता है। तो क्या Storable :: dclone कर रहा है? एक्सएस जादू? –

+3

चालाक! '' Storable' में 'store_hash' फ़ंक्शन] (http://cpansearch.perl.org/src/AMS/Storable-2.30/Storable.xs) इटरेटर की स्थिति को बचाता है, हैश के माध्यम से इसे स्टोर करता है, और फिर इसे पूरा होने पर पुनरावर्तक स्थिति को पुनर्स्थापित करता है। – mob

2

इस हैश कितना बड़ा है? इसके माध्यम से फिर से शुरू करने में कितना समय लगता है, जैसे कि आप पहुंच के समय की परवाह करते हैं?

बस एक ध्वज सेट और यात्रा के अंत के बाद कार्रवाई करते हैं:

my $print_it; 
while (my ($key,$val) = each %hash) { 
    $print_it = 1 if something_interesting_happens(); 
    ... 
} 

if ($print_it) { 
    foreach my $k (keys %hash) { print "$k => $hash{$k}\n" } 
} 

वहाँ प्रिंटआउट कोड में each का उपयोग नहीं करने का कोई कारण नहीं है, भी, जब तक आप कुंजी या द्वारा छँटाई पर योजना बना रहे थे कुछ कुछ।

1

चलो नहीं भूल जाते हैं कि keys %hash पहले से ही परिभाषित किया गया है, जब आप while पाश दर्ज करें: यह शायद कुछ इस तरह होगा। एक बस बाद में उपयोग के लिए एक सरणी में कुंजी रक्षा कर सकता था:

my @keys = keys %hash; 

while (my ($key,$val) = each %hash) { 

    if (something_interesting_happens()) { 

     print "$_ => $hash{$_}\n" for @keys; 
    } 
} 

गिरावट:

  • यह कम सुरुचिपूर्ण है (व्यक्तिपरक)
  • यह अगर %hash संशोधित किया गया है काम नहीं करेगा (लेकिन फिर क्यों एक पहली जगह में each का प्रयोग करेंगे)

उल्टा:

  • यह परहेज हैश नकल
1

नहीं वास्तव में से कम स्मृति का उपयोग करता है। each अविश्वसनीय रूप से नाजुक है। यह पुनरावृत्त हैश पर ही पुनरावृत्ति स्थिति संग्रहीत करता है, राज्य जिसे पर्ल के अन्य हिस्सों द्वारा पुन: उपयोग किया जाता है जब उन्हें इसकी आवश्यकता होती है। यह जानना बेहद सुरक्षित है कि यह मौजूद है, और हमेशा keys %hash के परिणाम से अपनी खुद की सूची को फिर से चालू करें, क्योंकि सूची में पुनरावृत्ति स्थिति for लूप के हिस्से के रूप में वर्णित रूप से संग्रहीत होती है, इसलिए अन्य चीजों से भ्रष्टाचार से प्रतिरक्षा है।

संबंधित मुद्दे

 संबंधित मुद्दे