सरणी में बहुत सारे डेटा हैं और मुझे दो तत्वों को हटाने की आवश्यकता है।
नीचे कोड स्निपेट का उपयोग किया जा रहा है,
my @array = (1,2,3,4,5,5,6,5,4,9);
my $element_omitted = 5;
@array = grep { $_ != $element_omitted } @array;
सरणी में बहुत सारे डेटा हैं और मुझे दो तत्वों को हटाने की आवश्यकता है।
नीचे कोड स्निपेट का उपयोग किया जा रहा है,
my @array = (1,2,3,4,5,5,6,5,4,9);
my $element_omitted = 5;
@array = grep { $_ != $element_omitted } @array;
जवाबों:
यदि आप पहले से ही उस तत्व के सूचकांक को जानते हैं जिसे आप हटाना चाहते हैं, तो ब्याह का उपयोग करें।
यदि आप खोज कर रहे हैं तो Grep काम करता है।
यदि आपको इनमें से बहुत कुछ करने की आवश्यकता है, तो आप अपने सरणी को क्रमबद्ध क्रम में रखेंगे तो आपको बेहतर प्रदर्शन मिलेगा, क्योंकि तब आप आवश्यक सूचकांक खोजने के लिए द्विआधारी खोज कर सकते हैं।
यदि यह आपके संदर्भ में समझ में आता है, तो आप हटाए गए रिकॉर्ड के लिए "जादू मूल्य" का उपयोग करने पर विचार कर सकते हैं, बल्कि फिर उन्हें हटाकर, डेटा आंदोलन पर सहेजने के लिए - हटाए गए तत्वों को अपरिभाषित करने के लिए सेट करें, उदाहरण के लिए। स्वाभाविक रूप से, इसके अपने मुद्दे हैं (यदि आपको "लाइव" तत्वों की संख्या जानने की आवश्यकता है, तो आपको इसे अलग से ट्रैक करने की आवश्यकता है, आदि), लेकिन आपके आवेदन के आधार पर परेशानी के लायक हो सकता है।
वास्तव में अब संपादित करें कि मैं दूसरा रूप लेता हूं - ऊपर grep कोड का उपयोग न करें। जिस तत्व को आप हटाना चाहते हैं, उसके सूचकांक को खोजने के लिए यह अधिक कुशल होगा, फिर इसे हटाने के लिए ब्याह का उपयोग करें (जिस कोड को आपने सभी गैर-मिलान परिणामों को जमा किया है ..)
my $index = 0;
$index++ until $arr[$index] eq 'foo';
splice(@arr, $index, 1);
यह पहली घटना को हटा देगा। सभी घटनाओं को हटाना बहुत समान है, सिवाय इसके कि आप सभी इंडेक्स को एक पास में लाना चाहेंगे:
my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr;
बाकी को पाठक के लिए एक उत्साह के रूप में छोड़ दिया जाता है - याद रखें कि जैसे ही आप इसे विभाजित करते हैं, सरणी बदल जाती है!
Edit2 जॉन सिराकुसा ने सही ढंग से कहा कि मेरे उदाहरण में एक बग था .. निश्चित, उस बारे में क्षमा करें।
my ($index) = grep { $arr[$_] eq 'foo' } 0..$#arr; if (defined $index) {splice(@arr, $index, 1); }
- पहले मैच के लिए
यह कुछ आप बहुत कुछ करने जा रहे हैं? यदि हां, तो आप एक अलग डेटा संरचना पर विचार करना चाह सकते हैं। Grep हर बार पूरे एरे को सर्च करने वाला है और एक बड़े एरे के लिए काफी महंगा हो सकता है। यदि गति एक मुद्दा है तो आप इसके बजाय एक हैश का उपयोग करने पर विचार कर सकते हैं।
आपके उदाहरण में, कुंजी संख्या होगी और मूल्य उस संख्या के तत्वों की गिनती होगी।
यदि आप बदलते हैं
my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr;
सेवा
my @del_indexes = reverse(grep { $arr[$_] eq 'foo' } 0..$#arr);
यह पहले सरणी के पीछे से तत्वों को हटाकर सरणी के पुनर्निधारण के मुद्दे से बचा जाता है। एक फॉरेस्ट लूप में एक स्प्लिस () डालना @arr को साफ करता है। अपेक्षाकृत सरल और पठनीय ...
foreach $item (@del_indexes) {
splice (@arr,$item,1);
}
तुम splicing के बजाय सरणी टुकड़ा करने की क्रिया का उपयोग कर सकते हैं। ग्रेप उन सूचकांकों को वापस करने के लिए जिन्हें आप रखना चाहते हैं और स्लाइसिंग का उपयोग करें:
my @arr = ...;
my @indicesToKeep = grep { $arr[$_] ne 'foo' } 0..$#arr;
@arr = @arr[@indiciesToKeep];
@arr = @arr[grep ...]
जो मुझे विशेष रूप से पसंद है। मुझे यकीन नहीं है कि यह कितना कुशल है, लेकिन मैं इसका उपयोग शुरू करने जा रहा हूं क्योंकि यह अन्य समाधानों से बदतर नहीं हो सकता है।
शेष पोस्ट दस्तावेजों को तत्वों में बदलने की कठिनाई को दस्तावेज में बदल देता splice
है। इस प्रकार, यह एक और अधिक पूर्ण उत्तर बना रहा है।
उन सूचियों को देखें जिनके माध्यम से आपको एक कुशल (यानी एक-पास) एल्गोरिथ्म के माध्यम से जाना जाता है ताकि सूची आइटम पर परीक्षणों को अनुक्रमित किया जा सके। और यह बिल्कुल भी सहज नहीं है।
sub array_remove ( \@& ) {
my ( $arr_ref, $test_block ) = @_;
my $sp_start = 0;
my $sp_len = 0;
for ( my $inx = 0; $inx <= $#$arr_ref; $inx++ ) {
local $_ = $arr_ref->[$inx];
next unless $test_block->( $_ );
if ( $sp_len > 0 && $inx > $sp_start + $sp_len ) {
splice( @$arr_ref, $sp_start, $sp_len );
$inx = $inx - $sp_len;
$sp_len = 0;
}
$sp_start = $inx if ++$sp_len == 1;
}
splice( @$arr_ref, $sp_start, $sp_len ) if $sp_len > 0;
return;
}
undef
। इसके अलावा, रिंगो द्वारा लिंक किए गए डॉक से: "चेतावनी: सरणी मूल्यों पर कॉलिंग को जोर से हतोत्साहित किया जाता है। पर्ल व्यू तत्वों के अस्तित्व को हटाने या जांचने की धारणा वैचारिक रूप से सुसंगत नहीं है, और आश्चर्यजनक व्यवहार को जन्म दे सकती है।" (डॉक्टर में पिछले पैराग्राफ में सभी विवरण हैं)।
सरणी के 'कुछ' की सभी घटनाओं को हटा दें।
SquareCog के जवाब के आधार पर:
my @arr = ('1','2','3','4','3','2', '3','4','3');
my @dix = grep { $arr[$_] eq '4' } 0..$#arr;
my $o = 0;
for (@dix) {
splice(@arr, $_-$o, 1);
$o++;
}
print join("\n", @arr);
हर बार जब हम @arr
इंडेक्स को हटाते हैं, तो हटाने का अगला सही इंडेक्स होगा $_-current_loop_step
।
मुझे जो सबसे अच्छा मिला वह "अनडेफ" और "ग्रीप" का संयोजन था:
foreach $index ( @list_of_indexes_to_be_skiped ) {
undef($array[$index]);
}
@array = grep { defined($_) } @array;
यह चाल है! फेडरिको
grep
अंत में फिर उन्हें हटा देता है।
बस यह सुनिश्चित करने के लिए कि मेरे पास grep और मानचित्र समाधान हैं, पहले मिलान किए गए तत्वों की अनुक्रमणिका (जिन्हें निकालना है) की खोज करना और फिर सीधे अनुक्रमणिका की खोज किए बिना grep द्वारा तत्वों को निकालना। मुझे प्रतीत होता है कि सैम द्वारा प्रस्तावित पहला समाधान जब उनका सवाल पूछा गया था तो वह पहले से ही सबसे तेज था।
use Benchmark;
my @A=qw(A B C A D E A F G H A I J K L A M N);
my @M1; my @G; my @M2;
my @Ashrunk;
timethese( 1000000, {
'map1' => sub {
my $i=0;
@M1 = map { $i++; $_ eq 'A' ? $i-1 : ();} @A;
},
'map2' => sub {
my $i=0;
@M2 = map { $A[$_] eq 'A' ? $_ : () ;} 0..$#A;
},
'grep' => sub {
@G = grep { $A[$_] eq 'A' } 0..$#A;
},
'grem' => sub {
@Ashrunk = grep { $_ ne 'A' } @A;
},
});
परिणाम है:
Benchmark: timing 1000000 iterations of grem, grep, map1, map2...
grem: 4 wallclock secs ( 3.37 usr + 0.00 sys = 3.37 CPU) @ 296823.98/s (n=1000000)
grep: 3 wallclock secs ( 2.95 usr + 0.00 sys = 2.95 CPU) @ 339213.03/s (n=1000000)
map1: 4 wallclock secs ( 4.01 usr + 0.00 sys = 4.01 CPU) @ 249438.76/s (n=1000000)
map2: 2 wallclock secs ( 3.67 usr + 0.00 sys = 3.67 CPU) @ 272702.48/s (n=1000000)
M1 = 0 3 6 10 15
M2 = 0 3 6 10 15
G = 0 3 6 10 15
Ashrunk = B C D E F G H I J K L M N
जैसा कि बीते हुए समय के अनुसार दिखाया गया है, किसी भी प्रकार के grep या मानचित्र परिभाषित इंडेक्स का उपयोग करके हटाए गए फ़ंक्शन को लागू करने का प्रयास करना बेकार है। सीधे सीधे हटाओ।
परीक्षण करने से पहले मैं सोच रहा था कि "मैप 1" सबसे कुशल होगा ... मुझे बेंचमार्क मेरे अनुमान पर अधिक बार भरोसा करना चाहिए। ;-)
इसी तरह का एक कोड मैंने एक बार स्ट्रिंग के एक सरणी से SB.1 से शुरू नहीं होने वाले तारों को हटाने के लिए लिखा था
my @adoSymbols=('SB.1000','RT.10000','PC.10000');
##Remove items from an array from backward
for(my $i=$#adoSymbols;$i>=0;$i--) {
unless ($adoSymbols[$i] =~ m/^SB\.1/) {splice(@adoSymbols,$i,1);}
}