लूप के लिए ब्रेक के बिना, सरणी और हटाने वाले आइटम के माध्यम से लूपिंग


462

मेरे पास लूप के लिए निम्नलिखित है, और जब मैं splice()किसी आइटम को निकालने के लिए उपयोग करता हूं, तो मुझे लगता है कि 'सेकंड' अपरिभाषित है। अगर यह अपरिभाषित है तो मैं जांच कर सकता था, लेकिन मुझे लगता है कि ऐसा करने के लिए शायद अधिक सुरुचिपूर्ण तरीका है। इच्छा बस एक आइटम को हटाने और जारी रखने के लिए है।

for (i = 0, len = Auction.auctions.length; i < len; i++) {
    auction = Auction.auctions[i];
    Auction.auctions[i]['seconds'] --;
    if (auction.seconds < 0) { 
        Auction.auctions.splice(i, 1);
    }           
}

11
पीछे की ओर चलने और लंबाई समायोजित करने के अलावा, आप केवल उन सदस्यों को भी शामिल कर सकते हैं जिन्हें आप एक नई सरणी में रखना चाहते हैं।
रॉबग

2
Auction.auctions[i]['seconds']--इसके बजाय आप क्यों कहते हैं auction.seconds--?
डॉन हैच

आप शायद पूर्वनिर्धारित फ़ंक्शन में देखना चाहते हैं .shift ();
राकू

जवाबों:


856

जब आप ए करते हैं .splice(), तो सरणी को फिर से अनुक्रमित किया जा रहा है , जिसका अर्थ है कि जब आप हटाए जाते हैं, तो आप एक इंडेक्स पर छोड़ देंगे, और आपका कैश्ड .lengthअप्रचलित है।

इसे ठीक करने के लिए, आपको या तो रिवर्स के iबाद डीट्रैक्शन की आवश्यकता होगी .splice(), या रिवर्स में ...

var i = Auction.auctions.length
while (i--) {
    ...
    if (...) { 
        Auction.auctions.splice(i, 1);
    } 
}

इस तरह से पुन: अनुक्रमण अगले आइटम को पुनरावृत्ति में प्रभावित नहीं करता है, क्योंकि अनुक्रमण केवल वर्तमान बिंदु से अंत तक के आइटम को प्रभावित करता है, और पुनरावृति में अगला आइटम वर्तमान बिंदु से कम है।


151

यह एक बहुत ही सामान्य मुद्दा है। समाधान पीछे की ओर लूप करना है:

for (var i = Auction.auctions.length - 1; i >= 0; i--) {
    Auction.auctions[i].seconds--;
    if (Auction.auctions[i].seconds < 0) { 
        Auction.auctions.splice(i, 1);
    }
}

इससे कोई फर्क नहीं पड़ता कि आप उन्हें अंत में पॉपिंग कर रहे हैं क्योंकि सूचक पीछे की तरफ जाते ही संरक्षित हो जाएंगे।


47

हर बार लूप के माध्यम से लंबाई को केवल शुरुआत के बजाय, जैसे:

for (i = 0; i < Auction.auctions.length; i++) {
      auction = Auction.auctions[i];
      Auction.auctions[i]['seconds'] --;
      if (auction.seconds < 0) { 
          Auction.auctions.splice(i, 1);
          i--; //decrement
      }
}

इस तरह आप सीमा से अधिक नहीं होंगे।

EDIT: इफ स्टेटमेंट में एक वृद्धि जोड़ा गया।


32

हालाँकि, आपका प्रश्न यह है कि ऐरे से तत्वों को हटाने के बारे में है , न कि तत्वों को हटाने के बारे में और (कुछ अन्य प्रसंस्करण के अलावा) कुशलता से हटाने के बारे में, मुझे लगता है कि किसी को भी इसी तरह की स्थिति में पुनर्विचार करना चाहिए।

इस दृष्टिकोण की एल्गोरिदमिक जटिलता O(n^2)ब्याह समारोह के रूप में है और लूप के लिए दोनों सरणी के ऊपर से पुनरावृति होती है (सबसे खराब स्थिति में सरणी के सभी तत्व अलग हो जाते हैं)। इसके बजाय आप बस आवश्यक तत्वों को नए सरणी में धकेल सकते हैं और फिर बस उस सरणी को वांछित चर में असाइन कर सकते हैं (जो कि बस पुनरावृत्त हुआ था)।

var newArray = [];
for (var i = 0, len = Auction.auctions.length; i < len; i++) {
    auction = Auction.auctions[i];
    auction.seconds--;
    if (!auction.seconds < 0) { 
        newArray.push(auction);
    }
}
Auction.auctions = newArray;

ES2015 के बाद से हम Array.prototype.filterइसे एक लाइन में फिट करने के लिए उपयोग कर सकते हैं :

Auction.auctions = Auction.auctions.filter(auction => --auction.seconds >= 0);


10

यदि आप ईएस 6 + का उपयोग कर रहे हैं, तो सिर्फ एरे.फिल्टर पद्धति का उपयोग क्यों न करें?

Auction.auctions = Auction.auctions.filter((auction) => {
  auction['seconds'] --;
  return (auction.seconds > 0)
})  

ध्यान दें कि फ़िल्टर पुनरावृत्ति के दौरान सरणी तत्व को संशोधित करना केवल वस्तुओं के लिए काम करता है और आदिम मूल्यों की सरणी के लिए काम नहीं करेगा।


9

एक बार एक सरणी तत्वों को पचाने के लिए एक और सरल उपाय:

while(Auction.auctions.length){
    // From first to last...
    var auction = Auction.auctions.shift();
    // From last to first...
    var auction = Auction.auctions.pop();

    // Do stuff with auction
}

8

ब्याह के उचित उपयोग के लिए यहां एक और उदाहरण दिया गया है। यह उदाहरण 'सरणी' से 'विशेषता' को निकालने वाला है।

for (var i = array.length; i--;) {
    if (array[i] === 'attribute') {
        array.splice(i, 1);
    }
}

8

एक लूप में कोड वाले स्प्लिस () वाले प्रत्येक बहुत ही मूल प्रश्न का उत्तर देने वाले प्रत्येक व्यक्ति के लिए, जो समय O (n 2 ) चला रहा है, या जिसने इस तरह के उत्तर को अपवर्तित किया है, सात साल के दौरान जब से यह प्रश्न पोस्ट किया गया था: आपको चाहिए लज्जित होना

यहाँ इस सरल रैखिक समय समस्या का एक सरल रैखिक समय समाधान है।

जब मैं इस स्निपेट को n = 1 मिलियन के साथ चलाता हूं, तो प्रत्येक कॉल filterInPlace () में .013 सेकंड से .016 सेकंड तक चलती है। एक द्विघात समाधान (उदाहरण के लिए स्वीकृत उत्तर) एक लाख बार या तो ले जाएगा।

// Remove from array every item such that !condition(item).
function filterInPlace(array, condition) {
   var iOut = 0;
   for (var i = 0; i < array.length; i++)
     if (condition(array[i]))
       array[iOut++] = array[i];
   array.length = iOut;
}

// Try it out.  A quadratic solution would take a very long time.
var n = 1*1000*1000;
console.log("constructing array...");
var Auction = {auctions: []};
for (var i = 0; i < n; ++i) {
  Auction.auctions.push({seconds:1});
  Auction.auctions.push({seconds:2});
  Auction.auctions.push({seconds:0});
}
console.log("array length should be "+(3*n)+": ", Auction.auctions.length)
filterInPlace(Auction.auctions, function(auction) {return --auction.seconds >= 0; })
console.log("array length should be "+(2*n)+": ", Auction.auctions.length)
filterInPlace(Auction.auctions, function(auction) {return --auction.seconds >= 0; })
console.log("array length should be "+n+": ", Auction.auctions.length)
filterInPlace(Auction.auctions, function(auction) {return --auction.seconds >= 0; })
console.log("array length should be 0: ", Auction.auctions.length)

ध्यान दें कि यह नया सरणी बनाने के बजाय मूल सरणी को संशोधित करता है; इसे इस तरह से करना फायदेमंद हो सकता है, जैसे कि इस मामले में कि सरणी प्रोग्राम की एकल मेमोरी टोंटी है; उस स्थिति में, आप एक ही आकार का एक और सरणी भी अस्थायी रूप से नहीं बनाना चाहते हैं।


मुझे एहसास नहीं था कि आप एक सरणी की लंबाई असाइन कर सकते हैं!
माइकल

मुझे नहीं पता था कि Array.splice(i,1)हर बार एक नई व्यूह रचना होगी। मैं बहुत शर्मिंदा हूं।
१०

2
@dehart हा, अच्छा :-) वास्तव में यह हर बार एक नई सरणी उदाहरण नहीं बनाता है; लेकिन इसमें हर उस वस्तु को टक्कर देना होता है जिसका सूचकांक i से नीचे की ओर अधिक होता है, जो औसत n / 2 धक्कों पर होता है।
डॉन हैच

1

इस धागे पर पहले से ही बहुत सारे अद्भुत जवाब हैं। हालाँकि मैं अपने अनुभव को तब साझा करना चाहता था जब मैंने ES5 संदर्भ में "एरीथ एलीमेंट को हटा दें" को हल करने की कोशिश की।

जावास्क्रिप्ट सरणियों में शुरू या अंत से तत्वों को जोड़ने / हटाने के लिए अलग-अलग तरीके हैं। य़े हैं:

arr.push(ele) - To add element(s) at the end of the array 
arr.unshift(ele) - To add element(s) at the beginning of the array
arr.pop() - To remove last element from the array 
arr.shift() - To remove first element from the array 

आवश्यक रूप से उपरोक्त विधियों में से कोई भी सरणी से nth तत्व को निकालने के लिए सीधे उपयोग नहीं किया जा सकता है।

ध्यान देने योग्य तथ्य यह है कि यह जावा इट्रेटर के उपयोग के विपरीत है जिसके कारण पुनरावृत्ति करते समय एक संग्रह के लिए nth तत्व को निकालना संभव है।

यह मूल रूप Array.spliceसे nth तत्व को हटाने के लिए केवल एक सरणी विधि के साथ हमें छोड़ता है (ऐसी अन्य चीजें हैं जो आप इन विधियों के साथ भी कर सकते हैं, लेकिन इस प्रश्न के संदर्भ में मैं तत्वों को हटाने पर ध्यान केंद्रित कर रहा हूं)

Array.splice(index,1) - removes the element at the index 

यहाँ मूल उत्तर (टिप्पणियों के साथ) से कॉपी किया गया कोड है:

var arr = ["one", "two", "three", "four"];
var i = arr.length; //initialize counter to array length 

while (i--) //decrement counter else it would run into IndexOutBounds exception
{
  if (arr[i] === "four" || arr[i] === "two") {
    //splice modifies the original array
    arr.splice(i, 1); //never runs into IndexOutBounds exception 
    console.log("Element removed. arr: ");

  } else {
    console.log("Element not removed. arr: ");
  }
  console.log(arr);
}

एक और उल्लेखनीय तरीका है Array.slice। हालाँकि इस विधि का वापसी प्रकार हटाए गए तत्व हैं। इसके अलावा यह मूल सरणी को संशोधित नहीं करता है। संशोधित कोड स्निपेट निम्नानुसार है:

var arr = ["one", "two", "three", "four"];
var i = arr.length; //initialize counter to array length 

while (i--) //decrement counter 
{
  if (arr[i] === "four" || arr[i] === "two") {
    console.log("Element removed. arr: ");
    console.log(arr.slice(i, i + 1));
    console.log("Original array: ");
    console.log(arr);
  }
}

कहा गया है कि, हम अभी भी Array.sliceनीचे दिखाए गए अनुसार nth तत्व को निकालने के लिए उपयोग कर सकते हैं। हालाँकि यह बहुत अधिक कोड है (इसलिए अक्षम है)

var arr = ["one", "two", "three", "four"];
var i = arr.length; //initialize counter to array length 

while (i--) //decrement counter 
{
  if (arr[i] === "four" || arr[i] === "two") {
    console.log("Array after removal of ith element: ");
    arr = arr.slice(0, i).concat(arr.slice(i + 1));
    console.log(arr);
  }

}

Array.sliceविधि ला redux कार्यात्मक प्रोग्रामिंग में अचल स्थिति प्राप्त करने के लिए अत्यंत महत्वपूर्ण है


ध्यान दें कि अधिक कोड किसी कोड की दक्षता का माप नहीं होना चाहिए।
कानो

0

लूपिंग करते समय एक सरणी को newArray में रिले करने का प्रयास करें:

var auctions = Auction.auctions;
var auctionIndex;
var auction;
var newAuctions = [];

for (
  auctionIndex = 0; 
  auctionIndex < Auction.auctions.length;
  auctionIndex++) {

  auction = auctions[auctionIndex];

  if (auction.seconds >= 0) { 
    newAuctions.push(
      auction);
  }    
}

Auction.auctions = newAuctions;

0

काम करने वाले दो उदाहरण:

(Example ONE)
// Remove from Listing the Items Checked in Checkbox for Delete
let temp_products_images = store.state.c_products.products_images
if (temp_products_images != null) {
    for (var l = temp_products_images.length; l--;) {
        // 'mark' is the checkbox field
        if (temp_products_images[l].mark == true) {
            store.state.c_products.products_images.splice(l,1);         // THIS WORKS
            // this.$delete(store.state.c_products.products_images,l);  // THIS ALSO WORKS
        }
    }
}

(Example TWO)
// Remove from Listing the Items Checked in Checkbox for Delete
let temp_products_images = store.state.c_products.products_images
if (temp_products_images != null) {
    let l = temp_products_images.length
    while (l--)
    {
        // 'mark' is the checkbox field
        if (temp_products_images[l].mark == true) {
            store.state.c_products.products_images.splice(l,1);         // THIS WORKS
            // this.$delete(store.state.c_products.products_images,l);  // THIS ALSO WORKS
        }
    }
}


-2
for (i = 0, len = Auction.auctions.length; i < len; i++) {
    auction = Auction.auctions[i];
    Auction.auctions[i]['seconds'] --;
    if (auction.seconds < 0) {
        Auction.auctions.splice(i, 1);
        i--;
        len--;
    }
}

7
एक अच्छे उत्तर में हमेशा एक स्पष्टीकरण होगा कि क्या किया गया था और यह इस तरह से क्यों किया गया था, न केवल ओपी के लिए बल्कि भविष्य के आगंतुकों के लिए एसओ।
B001 B

-2

आप बस के माध्यम से देख सकते हैं और उपयोग कर सकते हैं shift()


3
कृपया इस विधि का उपयोग करके एक उदाहरण जोड़ें।
इवान
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.