6

I'm trying to loop through an array and delete and skip the elements until only one is existing. i've tried splicing but it messes up my loop because the element from arr[1] then becomes arr[0] etc.

Let's say there are 10 people. I'd like to remove person 1 then keep person 2 then remove person 3 and keep person 4. This pattern will go on until only one is left.

any kind of help will do.

KT.
  • 571
  • 3
  • 6
  • 19
  • What do you mean "until only one is left"? After one pass through the array you'll have cut it from 10 to 5 elements (people) - are you saying you want to keep repeating that process (with repeated passes through) until the array has only one element in it? – nnnnnn Mar 07 '12 at 05:14
  • If you want only one element... Then why do you need a loop? – trumank Mar 07 '12 at 05:21
  • @MathWizz, that was my thinking as well, the position of the remaining element can be calculated without the need for looping. – Cameron Mar 07 '12 at 05:58
  • Yes I will be repeating the process until there is only one left. – KT. Mar 07 '12 at 19:56

14 Answers14

29

Filter the falsy items:

var a=[1,2,"b",0,{},"",NaN,3,undefined,null,5];
var b=a.filter(Boolean); // [1,2,"b",{},3,5]
alexoviedo999
  • 6,761
  • 1
  • 26
  • 17
9

When you splice, just decrement your loop index.

There were lots of good suggestions, I'll post the code for the different options and you can decide which to use

Decrement index when splicing http://jsfiddle.net/mendesjuan/aFvVh/

var undef;
var arr = [1,2, undef, 3, 4, undef];
for (var i=0; i < arr.length; i++) {
    if ( arr[i] === undef ) {
        arr.splice(i,1);
        i--;
    }
}

Loop backwards http://jsfiddle.net/mendesjuan/aFvVh/1/

var undef;
var arr = [1,2, undef, 3, 4, undef];
for (var i=arr.length - 1; i >=0; i--) {
    if ( arr[i] === undef ) {
        arr.splice(i,1);
    }
}

Copy to new array http://jsfiddle.net/mendesjuan/aFvVh/2/

var undef;
var arr = [1,2, undef, 3, 4, undef];
var temp = [];
for (var i=0; i < arr.length; i++) {
    if ( arr[i] !== undef ) {
        temp.push(arr[i])
    }
}
arr = temp;

Use filter which is just a fancy way to create a new array

var undef;
var arr = [1,2, undef, 3, 4, undef];
arr = arr.filter(function(item){
    return item !== undef;
});

At the end of all those examples, arr will be [1,2,3,4]

Performance

IE 11, FF and Chrome agree that Array.splice is the fastest. 10 times (Chrome), 20 times (IE 11) as fast as Array.filter. Putting items into a new array was also slow when compared to Array.slice. See http://jsperf.com/clean-undefined-values-from-array2

I am really surprised to see IE lead the pack here, and to see Chrome behind FF and IE. I don't think I've ever run a test with that result.

Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
9

you should not change the collection during the iterating, not just JavaScript but all language, define a new array and add those ones you want to delete in it, and iterate that one later to delete from first one.

Simon Wang
  • 2,843
  • 1
  • 16
  • 32
  • You can change it, if you control the index. However, this is less error prone than my suggestion – Ruan Mendes Mar 07 '12 at 05:11
  • 3
    How about adding the ones you want to _keep_ to the second array, then at the end replace the first array with the second? Saves having to iterate through a second time. – nnnnnn Mar 07 '12 at 05:16
  • My opinion is just we should try to keep our code simple and easy to read, my expedience just tell me that writing a strange complex loop can only bring bugs and confuse others – Simon Wang Mar 07 '12 at 06:48
  • I misread Simon's suggestion, the real easy way to do it is what nnnnnn suggested (under this answer), copy it to a new array – Ruan Mendes Mar 07 '12 at 17:49
  • I ended up using 3 arrays, first as the original which is the basis for the loop. within the loop 2 arrays are used. the second array contains those that are skipped in that iteration and another is an empty array. at the end of each iteration, i do this. `arr1 = arr2;` `arr2 = arr3;` I'm not sure if this is the best solution but it made sense like what Simon said to make it simpler and it worked. – KT. Mar 07 '12 at 20:21
3

If by any chance you're using CoffeeScript then to remove undefined from Array do this

values = ['one', undefined]
values = (item for item in values when item != undefined) 

values
/* => ['one'] */
equivalent8
  • 13,754
  • 8
  • 81
  • 109
3

Loop backwards. (Removing items will thus not affect the indexes of elements not yet processed.)

nnnnnn
  • 147,572
  • 30
  • 200
  • 241
1

Surprisingly, nobody have answered the best and correct way:

  1. Create new array
  2. Iterate on the old array and only push the elements you want to keep to the new array

some credit goes to @nnnnnn comment

Community
  • 1
  • 1
ajax333221
  • 11,436
  • 16
  • 61
  • 95
0
>If you are getting undefined during deletion of the key-pair, Then to prevent "undefined" you can try code given below to delete key-pair  


   1) test = ["1","2","3","4",""," "];
   2) var delete = JSON.stringify(test);   
      case1) delete = delete.replace(/\,""/g,'');  
         or  
      case2) delete = delete.replace(/\," "/g,'');  
         or  
      case3) delete = delete.replace(/\,null/g,'');  

   3) var result = JSON.parse(delete);  
Vishal Kumar
  • 1,290
  • 14
  • 15
0

simply [NaN, undefined, null, 0, 1, 2, 2000, Infinity].filter(Boolean)

Judith lobo
  • 131
  • 4
0

Not gathering exactly what you are trying to achieve, but I feel you are relying on the position index of an item in the array to continue with your program. I would in this case suggest a hashed array, i.e., a Key<>Value pair array.

In which case, arr["2"] always points at the item you had placed in it originally. Thus you can logically/numerically loop through, while not worrying about changes in position.

Beware of the Type Conversion risk and pitfalls!

bPratik
  • 6,894
  • 4
  • 36
  • 67
0

Your best bet is to create a duplicate of the array, then splice from the original.

Or just go using a collection (key->value) and just delete the key eg

 People = {a: "Person A", b: "Person B", c:"Person C"};
 delete People.a;
 delete People.c;  //now the People collection only has 1 entry.

You can replace a,b,c with numbers just using it as an example,

 People = {0: "Person A", 1: "Person B", 2:"Person C"};
 delete People[0];
 delete People[1];
DdD
  • 453
  • 4
  • 19
0
function removeUndefined(array)
{
    var i = 0;
    while (i < array.length)
        if (typeof array[i] === 'undefined')
            array.splice(i, i);
        else
            i++;
    return array;
}

EDIT: I wrote this based on the title. Looks like the question asks something completely different.

trumank
  • 2,704
  • 3
  • 22
  • 31
0

this is a sample for you

<script lanauge = "javascript">
    var arr = ["1","2","3","4"];
    delete arr[1];// arr[1] is undefined
    delete arr[2];// arr[2] is undefined

    // now arr.length is 4

    var todelete = [];
    for (i = 0 ; i < arr.length ;i++)
    {
        if (typeof arr[i] == 'undefined') todelete.push(i);
    }

    todelete.sort(function(a, b) { return b-a }); // make the indeies from big to small

    for (i = 0;i < todelete.length; i ++)
    {
        arr.splice(todelete[i],1);
    }

    // now arr.length is 2

</script>
shenhengbin
  • 4,236
  • 1
  • 24
  • 33
  • That `.sort()` method isn't doing what the comment says it is. Without a callback function it will do an ascending lexicographic sort. – nnnnnn Mar 07 '12 at 05:31
0

This may not be what you want, but you can easily calculate what the final element at the end of this procedure will be, then just grab it. Assuming that the elements of the array are contiguous and start at arr[0], you can find:

var logBase2OfLength = Math.floor(Math.log(arr.length) / Math.log(2));
var finalElement = arr[(1 << logBase2OfLength) - 1];

Basically, if you take the integer power of 2 that is less than or equal to the number of elements in your array, that is the position of the element that will remain after all of the looping and deleting.

Cameron
  • 1,675
  • 11
  • 12
-1
  while(yourarray.length>1) //only one left
    {
    // your code
    }
avgusti
  • 123
  • 1
  • 2
  • 6