问题
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;
}
回答1:
You have two options:
Work in reverse order, or
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);
回答2:
Traverse from end to start of list and use 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(''));
来源:https://stackoverflow.com/questions/62278398/how-to-remove-list-of-splices-from-array-in-javascript