Given a 2D array I am looking for an elegant and performant way to divide up a 1D array of words
given a start index and end index.
// pass this in as an arg
var trim = [
[3, 4], // remove two words at index 3 and 4
[9, 10] // remove two words at index 9 and 10
]; // use this to reformat
var words = [
{ word: "hello", st: 0 },
{ word: "stack-overflow", st: 0.5 },
{ word: "lets", st: 1 },
{ word: "remove", st: 1.5 },
{ word: "some", st: 2 },
{ word: "words", st: 2.5 },
{ word: "efficiently", st: 3 },
{ word: "lets", st: 3.5 },
{ word: "do", st: 4 },
{ word: "it", st: 4.5 },
{ word: "yay", st: 5 }
];
// this is the result I am looking for
var result = [
[
{ word: "hello", st: 0 },
{ word: "stack-overflow", st: 0.5 },
{ word: "lets", st: 1 }
],
[
{ word: "words", st: 2.5 },
{ word: "efficiently", st: 3 },
{ word: "lets", st: 3.5 },
{ word: "do", st: 4 }
]
];
This is the best I could do, missing return as 2D array
words.reduce((acc, curr, i) => {
const wordBetween = trim.some(t => {
return t[0] <= i && t[1] >= i
});
console.log({wordBetween, curr})
if (wordBetween) {
return acc;
}
return [...acc, curr]
}, [])
CodePudding user response:
Pure elegance! And supreme performance! Jokes aside, this should convey the idea.
let start = 0;
let result = [];
for (let [end, newStart] of trim) {
result.push(words.slice(start, end));
start = newStart 1;
}
result.push(words.slice(start, words.length));
Note that 2 splits results in three chunks ( n splits give n 1 chunks ) so there might be an empty array at the start or end. This has precedence in string.split.
CodePudding user response:
we can make uses of JSON.stringify
to split up the objects.
const splitArrayBasedOnIndexes = (arr = [], indexToRemove = []) => {
indexToRemove = indexToRemove.flat(Infinity);
let result = JSON.stringify(arr.map((w, i) => {
if (indexToRemove.includes(i)) return null;
return w
}))
result = result.substring(1, result.lastIndexOf("]")).split("null").reduce((p, c) => {
if (c.substring(c.indexOf("{"), c.lastIndexOf("}") 1))
p.push(JSON.parse("[" c.substring(c.indexOf("{"), c.lastIndexOf("}") 1) "]"))
return p
}, []);
return result;
}
const words = [
{ word: "hello", st: 0 },
{ word: "stack-overflow", st: 0.5 },
{ word: "lets", st: 1 },
{ word: "remove", st: 1.5 },
{ word: "some", st: 2 },
{ word: "words", st: 2.5 },
{ word: "efficiently", st: 3 },
{ word: "lets", st: 3.5 },
{ word: "do", st: 4 },
{ word: "it", st: 4.5 },
{ word: "yay", st: 5 }
];
const trim = [
[3, 4],
[9, 10]
];
console.log(splitArrayBasedOnIndexes(words, trim));
CodePudding user response:
Here's a way to filter an array, removing some specified indexes...
const arrayWithoutIndexes = (array, indexes) => {
return array.filter((el, i) => !indexes.includes(i));
};
var words = [
{ word: "hello", st: 0 },
{ word: "stack-overflow", st: 0.5 },
{ word: "lets", st: 1 },
{ word: "remove", st: 1.5 },
{ word: "some", st: 2 },
{ word: "words", st: 2.5 },
{ word: "efficiently", st: 3 },
{ word: "lets", st: 3.5 },
{ word: "do", st: 4 },
{ word: "it", st: 4.5 },
{ word: "yay", st: 5 }
];
console.log(arrayWithoutIndexes(words, [1,4]));
EDIT: To handle several sets of indexes, producing a new set of edited words for each set of indexes, just map that function over the index input...
const arrayWithoutIndexes = (array, indexes) => {
// the map here just copies the word, so the result has new word objects
return array.filter((el, i) => !indexes.includes(i)).map(o => Object.assign({}, o));
};
var words = [
{ word: "hello", st: 0 },
{ word: "stack-overflow", st: 0.5 },
{ word: "lets", st: 1 },
{ word: "remove", st: 1.5 },
{ word: "some", st: 2 },
{ word: "words", st: 2.5 },
{ word: "efficiently", st: 3 },
{ word: "lets", st: 3.5 },
{ word: "do", st: 4 },
{ word: "it", st: 4.5 },
{ word: "yay", st: 5 }
];
let removeThese = [
[2, 3],
[4, 5]
];
let result = removeThese.map(indexes => arrayWithoutIndexes(words, indexes));
console.log(result)