如何从 JavaScript 中的数组中删除拼接列表?

How to remove list of splices from array in JavaScript?

我有索引列表:

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

以及来自 Scheme lisp 的 S-Expression 的标记列表。

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

从令牌中删除所有项目的最佳方法是什么。 (它假设删除 R7RS 中指定的内联命令 #;(foo bar)#;xxx)。

我可以用这个:

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

因为第一次调用拼接索引后会发生变化。从数组中删除所有指定范围的最简单方法是什么?

对于上下文,我有这个函数应该删除内联注释,我将计算索引与从数组中删除它们分开了,这是好方法吗?

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;
}

您有两个选择:

  1. 以相反的顺序工作,或者

  2. 跟踪您删除了多少,并在以后的索引中考虑到这一点

这是#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);

这是#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);

从列表的末尾遍历到列表的开头并使用copyWithin

function remove(dat, list) {
  const arr = [...dat];
  const is_remove = index =>
    list.some(([start, end]) => index >= start && index <= end);

  for (let i = arr.length - 1; i > -1; i--) {
    if (is_remove(i)) {
      arr.copyWithin(i, i + 1).pop();
    }
  }
  return arr;
}

function remove2(dat, list) {
  const arr = [...dat];
  let new_len = arr.length;
  for (let i = list.length - 1; i > -1; i--) {
    const [start, end] = list[i];
    arr.copyWithin(start, end + 1);
    new_len -= end - start + 1;
  }
  arr.length = new_len;
  return arr;
}

// Alternate way
const remove3 = (arr, list) =>
  arr.filter((_, i) => !list.some((rg) => i >= rg[0] && i <= rg[1]));


var remove_list = [ [ 7, 11 ], [ 12, 14 ] ];
var tokens = [
  '(',  'let', '(',   '(',
  'x',  '10',  ')',   '#;',
  '(',  'foo', 'bar', ')',
  '#;', 'xxx', ')',   '(',
  '*',  'x',   'x',   ')',
  ')'
];

console.log(remove(tokens,remove_list).join(''));
console.log(remove2(tokens,remove_list).join(''));
console.log(remove3(tokens,remove_list).join(''));