1

I have an array of objects and I want to remove a value by its index. I have a method, to which the value to be removed is passed, that finds the passed parameter value:

remove: (val) ->
  for el, index in @arr
    if el is val
      # remove el from @arr...

The CoffeeScript website says quite clearly that in order to replace the element I want, I have to do @arr[index] = 'something', but nothing is said for removing it entirely.

2 Answers 2

3

Just use .splice():

for index, elem in @arr
    @arr.splice index, 1 if elem is val

If you don't care about Internet Explorer 7 or 8, you can simplify it even more:

@arr.splice @arr.indexOf(val), 1

This assumes that the element is present in the array, otherwise it would remove the very last element. In case you need to check if it is present, you can use a little trick:

@arr.splice (@arr.indexOf(val)+1 or @arr.length+1)-1, 1

Compared to the "coffee only" filter solution, you get 4-8 times the performance (in Chrome):

Removing 5 random elements from an array with 10.000.000 integers

cumulative execution time after each removed element

filter method

  • 197ms
  • 422ms
  • 626ms
  • 847ms
  • 1087ms

splice method

  • 33ms
  • 83ms
  • 142ms
  • 198ms
  • 255ms

splice and indexOf method

  • 27ms
  • 70ms
  • 88ms
  • 116ms
  • 134ms

Test code - quick and dirty (doesn't account for randomly selecting the same value twice):

log "coffee method"
arr = [0..9999999]
length = arr.length
start = new Date().getTime()
for num in [1..5]
    val = Math.round(Math.random() * length)
    do (val) -> arr = (x for x in arr when x isnt val)
    log new Date().getTime()-start+"ms"

log "splice method"
arr = [0..9999999]
length = arr.length
start = new Date().getTime()
for num in [1..5]
    val = Math.round(Math.random() * length)
    for index, elem in arr
        arr.splice index, 1 if elem is val
    log new Date().getTime()-start+"ms"

log "splice method with indexOf()"
arr = [0..9999999]
length = arr.length
start = new Date().getTime()
for num in [1..5]
    val = Math.round(Math.random() * length)
    arr.splice arr.indexOf(val), 1
    log new Date().getTime()-start+"ms"

Demo: http://jsfiddle.net/j9CZz/1/

Sign up to request clarification or add additional context in comments.

11 Comments

Currently, I do it with .splice. That's the JavaScript way. I just want a more CoffeeScript approach.
But coffeescript USES Javascript...? Whatever you do in coffee, you end up with JS in the end, so the best performance and most natural thing would be to just use the native JS solution.
Can you remove an element from a javascript array while simultaneously iterating over it also?
Of course it uses JavaScript... what I meant here is whether I can use some of the benefits that CoffeeScript provides (if there are such in this case). In this case filters came more or less suitable... whether I'm going to use them or stick to the natural JS way, still not decided.
@Cupcake yes, this will keep iterating over the rest of the array while removing matching elements
|
0

The documentation gives an example of using filters, so maybe you could try that?:

remove: (val) -> @arr = (x for x in @arr when x isnt val)

1 Comment

This would not only create a second in-memory copy of the whole array (minus 1 element), but also iterate over all elements instead of just up to the element that has to be deleted. Plus, it needs like 3 times the code, creates 4 new vars and an anonymous function.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.