#javascript #arrays #duplicates
Вопрос:
Входные данные представляют собой массив, содержащий строки трех типов: буква L с присоединенной цифрой, буква R с присоединенной цифрой и буква D с присоединенной цифрой. Эти строки могут повторяться. Задача состоит в том, чтобы написать функцию, которая возьмет соседние Ds и уменьшит их до одного D с обновленной цифрой Ds, которые присутствовали раньше. Обратите внимание, что только соседние Ds должны быть уменьшены и подсчитаны. Примеры выходных данных, которые я хочу:
input: ['D1', 'D1', 'L1', 'D1', 'D1', 'D1', 'R1']
output: ['D2', 'L1', 'D3', 'R1']
input: ['R1', 'D1', 'L1', 'D1', 'D1', 'D1', 'D1', 'L1', 'R1', 'D1', 'D1', 'D1']
output: ['R1', 'D1', 'L1', 'D4', 'L1', 'R1', 'D3']
По-видимому, моя функция не работает по двум основным причинам: сращивание массива во время цикла (я пытаюсь избавиться от избыточного Ds), и я заставляю функцию выходить за рамки массива на последней итерации (arr[i 1].charAt(0) === ‘D’). Я не могу преодолеть эти проблемы.
function reduceD(arr) {
for (i = 0; i < arr.length; i ) {
let str = arr[i];
if (arr[i].charAt(0) === 'D' amp;amp; arr[i 1].charAt(0) === 'D') {
arr[i] = 'D' (Number(str[1]) 1);
arr.splice(i 1, 1);
}
}
return arr;
}
Ответ №1:
Пожалуйста, используйте функцию Array.reduce.
function reduceD(arr) {
const result = arr.reduce((total, val) => {
if(total.length === 0)
total.push(val);
else {
const last = total[total.length - 1];
const newValue = last.charAt(0) (Number(last.slice(1)) 1);
last.charAt(0) === val.charAt(0) ? total.splice(total.length - 1, 1, newValue) : total.push(val);
}
return total;
}, []);
return resu<
}
console.log(reduceD(['D1', 'D1', 'L1', 'D1', 'D1', 'D1', 'R1']));
console.log(reduceD(['R1', 'D1', 'L1', 'D1', 'D1', 'D1', 'D1', 'L1', 'R1', 'D1', 'D1', 'D1']));
Ответ №2:
Чтобы добавить к другому ответу: Если вы хотите выполнить итерацию по массиву при удалении элементов, сделайте это в обратном порядке, чтобы не пропустить ни одного элемента. Вот исправленная версия вашего кода и одна с простым циклом, в котором IMHO легче понять (и намного проще, чем Array.reduce
функция в другом ответе для начинающих)
Я согласен с другим ответом, хотя, это Array.reduce
путь для более опытных программистов, которые знают, как Array.reduce
работает.
// the fixed version of your code
function reduceD(arr) {
// iterate backwards to make the splice possible
// also note how the loop does never reach i == 0 but stops at 1 instead
for (let i = arr.length - 1; i > 0; i--) {
let str = arr[i];
if (arr[i].charAt(0) === 'D' amp;amp; arr[i - 1].charAt(0) === 'D') {
arr[i - 1] = 'D' (Number(str[1]) 1);
arr.splice(i, 1);
}
}
return arr;
}
// the IMHO simpler way of creating a new array
function buildingNewArray(arr) {
let out = [];
let dsFound = 0;
for (const elem of arr) {
if (elem.charAt(0) === 'D') {
dsFound ;
} else {
// there is no D in the current element
if (dsFound > 0) {
// add all found Ds as one
out.push('D' dsFound);
dsFound = 0;
}
// always output the current element to the output
out.push(elem);
}
}
// we're done with the loop but there might be some Ds to output
if (dsFound > 0) {
out.push('D' dsFound);
}
return out;
}
const arr1 = ['D1', 'D1', 'L1', 'D1', 'D1', 'D1', 'R1'];
const arr2 = ['R1', 'D1', 'L1', 'D1', 'D1', 'D1', 'D1', 'L1', 'R1', 'D1', 'D1', 'D1'];
console.log(buildingNewArray(arr1));
console.log(buildingNewArray(arr2));
console.log(reduceD(arr1));
console.log(reduceD(arr2));
Комментарии:
1. Спасибо вам, так круто и умно, как вы исправили мой код с помощью обратной итерации. Тем легче мне это понять, так как я новичок. Большое спасибо!
2. Ваше второе решение buildingNewArray Мне тоже нравится, я некоторое время смотрел на него, чтобы, наконец, понять логику, лежащую в его основе. То, что я пропустил раньше, — это трюк, чтобы вернуть счетчик Ds к нулю после его перемещения в новый массив, как вы сделали с dsFound = 0 внутри цикла. Мило!
Ответ №3:
Уменьшите массив до нового массива, если текущий элемент не является правильным символом или последний элемент в накопителе ( acc
) не начинается с правильного символа, нажмите текущий элемент. В противном случае увеличьте номер последнего элемента.
const isChar = (char, item) => !!item?.startsWith(char);
const incItem = item => `${item[0]}${ item.substring(1) 1}`;
const reduceD = (char, arr) =>
arr.reduce((acc, c) => {
if(!isChar(char, c) || !isChar(char, acc[acc.length - 1])) acc.push(c);
else acc[acc.length - 1] = incItem(acc[acc.length - 1]);
return acc;
}, []);
console.log(reduceD('D', ['D1', 'D1', 'L1', 'D1', 'D1', 'D1', 'R1'])); // ['D2', 'L1', 'D3', 'R1']
console.log(reduceD('D', ['R1', 'D1', 'L1', 'D1', 'D1', 'D1', 'D1', 'L1', 'R1', 'D1', 'D1', 'D1'])); // ['R1', 'D1', 'L1', 'D4', 'L1', 'R1', 'D3']