Search code examples
javascriptarrayssplice

How to remove list of splices from array in JavaScript?


I have list of indexes:

var remove_list = [ [ 7, 12 ], [ 12, 14 ] ];

and list of tokens of S-Expression from Scheme lisp.

var tokens = [
  '(',  'let', '(',   '(',
  'x',  '10',  ')',   '#;',
  '(',  'foo', 'bar', ')',
  '#;', 'xxx', ')',   '(',
  '*',  'x',   'x',   ')',
  ')'
];

what is the best way to remove all items from tokens. (it suppose to remove inline commands #;(foo bar) ad #;xxx as specified in R7RS).

I can use this:

for (let remove of remove_list) {
    tokens.splice(...remove);
}

because after first call to splice indexes will change. What is simplest way to remove all specified ranges from array?

And for context I have this function that should remove inline comments, I've splitted calculating the indexes from removing them from array, is this good approach?

function strip_s_comments(tokens) {
    var s_count = 0;
    var s_start = null;
    var remove_list = [];
    for (let i = 0; i < tokens.length; ++i) {
        const token = tokens[i];
        if (token === '#;') {
            if (['(', '['].includes(tokens[i + 1])) {
                s_count = 1;
                s_start = i;
            } else {
                remove_list.push([i, i + 2]);
            }
            i += 1;
            continue;
        }
        if (s_start !== null) {
            if ([')', ']'].includes(token)) {
                s_count--;
            } else if (['(', '['].includes(token)) {
                s_count++;
            }
            if (s_count === 0) {
                remove_list.push([s_start, i + 1]);
                s_start = null;
            }
        }
    }
    for (let remove of remove_list) {
        tokens.splice(...remove);
    }
    return tokens;
}

Solution

  • You have two options:

    1. Work in reverse order, or

    2. Keep track of how much you've removed and take that into account with later indexes

    Here's an example of #1:

    const reverse = remove_list.sort(([a], [b]) => b - a);
    for (const [begin, end] of reverse) {
        tokens.splice(begin, end - begin);
    }
    

    var remove_list = [ [ 7, 12 ], [ 12, 14 ] ];
    
    var tokens = [
      '(',  'let', '(',   '(',
      'x',  '10',  ')',   '#;',
      '(',  'foo', 'bar', ')',
      '#;', 'xxx', ')',   '(',
      '*',  'x',   'x',   ')',
      ')'
    ];
    
    const reverse = remove_list.sort(([a], [b]) => b - a);
    for (const [begin, end] of reverse) {
        tokens.splice(begin, end - begin);
    }
    
    console.log(tokens);

    Here's an example of #2:

    let removed = 0;
    for (const [begin, end] of remove_list) {
        removed += tokens.splice(begin - removed, end - begin).length;
    }
    

    var remove_list = [ [ 7, 12 ], [ 12, 14 ] ];
    
    var tokens = [
      '(',  'let', '(',   '(',
      'x',  '10',  ')',   '#;',
      '(',  'foo', 'bar', ')',
      '#;', 'xxx', ')',   '(',
      '*',  'x',   'x',   ')',
      ')'
    ];
    
    let removed = 0;
    for (const [begin, end] of remove_list) {
        removed += tokens.splice(begin - removed, end - begin).length;
    }
    
    console.log(tokens);