2013-05-08 6 views
6

पर्ल का निम्न स्निपेट हैश मान द्वारा संदर्भित सरणी के पहले 5 आइटम मुद्रित करना है, या यदि सरणी कम है तो कम।अप्रत्याशित रूप से लघु पर्ल स्लाइस

while (my ($key,$value) = each %groups) { 
    print "$key: \n"; 
    my @list = grep defined, @{$value}; 
    my @slice = grep defined, @list[0..4]; 
    foreach my $item (@slice) { 
     print " $item \n"; 
    } 
    print " (", scalar @slice, " of ", scalar @list, ")\n"; 
} 

मुझे नहीं लगता कि पहले grep defined आवश्यक है, लेकिन यह कोई नुकसान नहीं कर सकता है, और यह गारंटी चाहिए टुकड़ा से पहले कोई अपरिभाषित सरणी सदस्यों देखते हैं कि।

$groups{$key} =() unless defined $groups{$key}; 
    push @{$groups{$key}}, $value; 

अधिकांश समय यह ठीक काम करता है: दूसरा grep definedslice का परिणाम जब @list से कम 5.

%groups के बार-बार आमंत्रण की आबादी किया गया है में अपरिभाषित सरणी सदस्यों को निकालने में है

key1: 
    value1 
    value2 
    value3 
    value4 
    value5 
    (5 of 100) 

लेकिन कभी कभी - और मैं किस परिस्थिति में बाहर काम नहीं किया - मैं देख रहा हूँ:

key2: 
    value1 
    (1 of 5) 

key3: 
    value1 
    value2 
    (2 of 5) 

मैं मुद्रित सूची की लंबाई की उम्मीद है, और x(x of y) से min(5,y)

क्या इस व्यवहार का कारण बन सकता होने के लिए?

उत्तर

8

grep का उपयोग @list के लिए सरणी स्लाइस के साथ तत्वों को स्वत: सक्रिय करता है और सरणी को बढ़ाता है।

@foo = (1,2,3); 
@bar = @foo[0..9999]; 
print scalar @foo;    # => 3 

@foo = (1,2,3); 
@bar = grep 1, @foo[0..9999]; 
print scalar @foo;    # => 10000 

यह अन्य संदर्भों में भी होता है जहां पर्ल एक सरणी टुकड़ा पर लूप करना चाहता है।

@foo = (1,2,3); 
foreach (@foo[0..9999]) { } 
print scalar @foo;    # => 10000 

@foo = (1,2,3); 
@bar = map { } @foo[0..9999]; 
print scalar @foo;    # => 10000 

तो समाधान क्या हैं?

  1. श्रृंखला के लिए एक और अधिक जटिल अभिव्यक्ति या grep संकार्य

    @bar = grep 1, @foo[0..(@foo>=9999?9999:$#foo)]; 
    @bar = grep 1, @foo>=9999 ? @foo[0..9999] : @foo; 
    
  2. उपयोग एक अस्थायी सरणी चर का प्रयोग करें

    @bar = grep 1, @[email protected][0..9999] 
    
  3. (@FMc ने सुझाव दिया) map का उपयोग निर्धारित करने के लिए एक इंटरमीडिएट सरणी

    @bar = grep 1, map { $list[$_] } 0..9999; 
    
  4. बजाय सीधे सरणी

    @bar_indices = grep defined($foo[$_]), 0..9999; 
    @bar = @foo[@bar_indices]; 
    
    @bar = @foo[ grep defined($foo[$_]), 0..9999 ]; 
    
+0

आउच के साथ की तुलना में सरणी सूचकांक के साथ काम! क्या इसके आस-पास एक बेवकूफ (या कम से कम साफ) तरीका है? – slim

+0

मैं इसके बारे में सोच रहा हूं। ['कोई autovivification'] (http://search.cpan.org/perldoc?autovivification) दुर्भाग्य से मदद नहीं करता है। – mob

+0

'प्रिंट "(", स्केलर @ स्लिस, "", स्केलर (grep परिभाषित, @list), ") \ n"; "सही आउटपुट प्राप्त करता है। यद्यपि भविष्य के रखरखाव के लिए एक गोचा छोड़ सकते हैं। – slim

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