5

I have an array that is very dynamic, there are new elements all the time, and other elements are removed.. The problem is that sometimes, under some circumstances, it's possible some of the elements to stay in the array forever and that is NOT what I want. Every element should be removed from the array within 15 seconds, if not, the array should remove that element automatically.

For example, in the code below, we have an array with three elements:

var array = ['e1', 'e2', 'e3'];

After 5 seconds I am adding 2 more elements in the array:

array[3] = 'e4';
array[4] = 'e5';

Now, let's say that the first 3 elements are inserted in the array in 12:00:00pm, and the second 2 elements in 12:00:05pm. I want the first 3 elements to be removed in 12:00:15pm, and the second 2 elements in 12:00:20pm......Etc....

Are there any ideas on how to solve this problem?

3 Answers3

4

Generally, when you are adding items to an array, you don't want to assume the position they will exist at. Instead of array[3] = 'e4', do array.push('e4'). This will make your life easier, and less bug-prone.

Because you need to associate times with each item, it might be wise to use objects for this in place of strings.

// create the array and push some objects into it
var array = []
array.push({createdAt: Date.now(), value: 'asdf'})
array.push({createdAt: Date.now(), value: 'asdf'})

Then, in an interval, you can check the createdAt values of each of the objects and decide if you want to kick them out of the array.

var maxLifespan = 5000
// check once per second
setInterval(function checkItems(){
    array.forEach(function(item){
        if(Date.now() - maxLifespan > item.createdAt){
            array.shift() // remove first item
        }
    })
}, 1000)

Using array.shift() assumes that you will always push new items onto the end of the array, so they will always be sorted chronologically.

If you need the array to be not chronologically sorted, then you'd need to use a method for removing elements at a specific index in an array (hint: NOT delete). Use array.splice to achieve this.

posit labs
  • 8,951
  • 4
  • 36
  • 66
  • This solution looks great, but can you tell me how to remove the items by value manually? Because sometimes, the user removes the elements before the timeout. – Hristijan Ilieski Sep 23 '16 at 22:17
  • Use array.splice to remove elements from the array. I've expanded the answer. – posit labs Sep 23 '16 at 22:21
  • Hmmm, I can't use array.splice because I don't know at what position is the value that I want to remove. For example if I have two values, "v1" and "v2", I don't know if v1 is at position 0, or 1. I only know that the item in the array that contains v1 is no longer needed. – Hristijan Ilieski Sep 23 '16 at 22:27
  • See this other SO answer: http://stackoverflow.com/questions/8668174/indexof-method-in-an-object-array – posit labs Sep 24 '16 at 00:10
3

You'll need to store a reference to when you inserted the values into the array in order to be able to remove them at a certain point. You might want to use a plain JavaScript object for this:

var map = {};

map[Date.now()] = ['a', 'b'];
console.log(map);

setTimeout(function() {
  map[Date.now()] = ['c', 'd'];
  console.log(map);
}, 5000);

setInterval(function() {
  var times = Object.keys(map);
  
  times.forEach(function(time) {
    if(Date.now() > (+time + 14000)) {
      delete map[time];
    }
  });
  
  console.log(map);
}, 1000);

Essentially I'm saving the times as the keys, and the array of items as the value. (Click "Run code snippet" above to see the console output to see how it behaves).

Basically we set up a "cron job" (simple setInterval) that runs every second and checks if the time the key was created is less than 14 seconds ago (not 15 seconds, since the cron job runs every second). Then it simply deletes that key from the object.

Josh Beam
  • 19,292
  • 3
  • 45
  • 68
2

You can add elements to the array with a function like this:

function insert(array, element) {
    array.push(element);

    setTimeout(() => {
        const index = array.indexOf(element);
        if (index >= 0) {
            array.splice(index, 1);
        }
    }, 15000);
}

This way you would make sure that the element is removed after ~15 seconds no matter what. Obviously it will work 100% correctly with objects/arrays (referential types), but if you store primitives like strings or numbers then if you have more than 1 such primitive value in the array, you might end up removing the other copy of the value, but in the end every element gets removed after ~15 seconds.

Azamantes
  • 1,435
  • 10
  • 15