Как добавить значение в массиве к значениям до и после него - PullRequest
0 голосов
/ 30 марта 2019

Я пытаюсь превратить массив чисел в шаги значения целочисленного элемента, отличного от нуля, т.е.

spread([0,0,n,0,0] returns => 
[0 + n-2, 0 + n-1, n, 0 + n -1, 0 + n - 2]

spread([0,0,0,n,0,2]) returns => 
[0+n-3, 0+n-2, 0+n-1, n ,(2-1)+(n-1) ,2 + n-2]

spread([0,0,0,4,0,0,0]) returns => [1,2,3,4,3,2,1]

spread([0,0,0,3,0,2,0]) returns => [0,1,2,3,3,3,1]

spread([3,0,0,0]) returns => [3,2,1,0]

и т. Д.

Я пробовал традиционный цикл for,Я пытался forEach, даже array.map, но ничего не работает, как ожидалось

Вот то, что я пытался, но это не работает

function pop(balloon) {
  let res = [];

  for (let i = 0; i < balloon.length; i++) {

    let n = balloon[i];
    let before = balloon[i - 1];
    let after = balloon[i + 1];

    if (n !== 0 && i < balloon.length - 1) {
      res.push(before + n - 1);
      res.push(n);
      res.push(after + n - 1);

    } else {
      res.push(n);
    }

  }
  return res;
}

const array1 = [0, 0, 0, 0, 4, 0, 0, 3, 0]
const array2 = [0, 0, 2, 0, 0]

console.log(pop(array1)) // returns[0, 0, 0, 0, 3, 4, 3, 0, 0, 2, 3, 2, 0]
// expected output => [0, 1, 2, 3, 4, 4, 4, 4, 2]

console.log(pop(array2)) // returns[0, 0, 1, 2, 1, 0, 0]
// expected output => [0, 1, 2, 1, 0]

Ответы [ 4 ]

2 голосов
/ 30 марта 2019

Вы можете уменьшить массив, используя копию массива, и перейти влево и вправо с помощью рекурсивной функции, которая проверяет значение для распространения и индекс.

function spread(array) {
    return array.reduce((r, v, i, a) => {
        const
            iter = (v, i, d) => {
                if (v < 1 || !(i in a)) return;
                r[i] += v;
                iter(v - 1, i + d, d);
            };
        iter(v - 1, i - 1, -1);
        iter(v - 1, i + 1, 1);
        return r;
    }, array.slice());
}

console.log(...spread([0, 0, 0, 4, 0, 0, 0])); // [1, 2, 3, 4, 3, 2, 1]
console.log(...spread([0, 0, 0, 3, 0, 2, 0])); // [0, 1, 2, 3, 3, 3, 1]
console.log(...spread([3, 0, 0, 0]));          // [3, 2, 1, 0]

Другой подход, перемещая массивы и добавляя их.

function spread(array) {
    const dec = v => Math.max(v - 1, 0);

    var result = array.slice(),
        temp = array.slice(1).map(v => Math.max(v - 1, 0)),
        offset;
    
    while (temp.length) {
        temp.forEach((v, i) => result[i] += v);
        temp = temp.slice(1).map(dec);
    }

    temp = array.slice(0, -1).map(dec);
    while (temp.length) {
        offset = result.length - temp.length;
        temp.forEach((v, i) => result[i + offset] += v);
        temp = temp.slice(0, -1).map(dec);
    }
    return result;
}

console.log(...spread([0, 0, 0, 4, 0, 0, 0])); // [1, 2, 3, 4, 3, 2, 1]
console.log(...spread([0, 0, 0, 3, 0, 2, 0])); // [0, 1, 2, 3, 3, 3, 1]
console.log(...spread([3, 0, 0, 0]));          // [3, 2, 1, 0]
1 голос
/ 31 марта 2019

Как-то "олдскул", но вроде работает:

let spread = a => {

    let add = a.map(_ => 0);

    a.forEach((x, i) => {
        for (let c = 1; x > 1 && c < a.length; c++, x--) {
            add[i + c] += x - 1;
            add[i - c] += x - 1;
        }
    });

    return a.map((x, i) => x + add[i]);
};

//

console.log(spread([0, 0, 0, 4, 0, 0, 0]).join())
console.log(spread([0, 0, 0, 3, 0, 2, 0]).join())
console.log(spread([3, 0, 0, 0, 0, 0]).join())
1 голос
/ 30 марта 2019

Один довольно простой метод, если не самый эффективный, - это создать квадратную сетку со строкой для каждого значения, либо всех нулей, либо по убыванию от одного ненулевого значения, как описано, а затем просто добавить столбцы.

Вот моя версия:

const pop = arr => arr.map(
  (n, i) => n == 0 
    ? Array(arr.length).fill(0) 
    : arr.map((_, j) => Math.max(n - Math.abs(j - i), 0))
).reduce((as, bs) => as.map((a, i) => a + bs[i]))

console.log(...pop([0, 0, 2, 0, 0]))             //~> [0, 1, 2, 1, 0]
console.log(...pop([3, 0, 0, 0]))                //~> [3, 2, 1, 0]
console.log(...pop([0, 0, 0, 3, 0, 2, 0]))       //~> [0, 1, 2, 3, 3, 3, 1]
console.log(...pop([0, 0, 0, 4, 0, 0, 0]))       //~> [1, 2, 3, 4, 3, 2, 1]
console.log(...pop([0, 0, 0, 0, 4, 0, 0, 3, 0])) //~> [0, 1, 2, 3, 4, 4, 4, 4, 2]

Обратите внимание, что промежуточный результат (после map, до reduce) для этого последнего выглядит следующим образом:

[
  [0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 1, 2, 3, 4, 3, 2, 1, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 1, 2, 3, 2],
  [0, 0, 0, 0, 0, 0, 0, 0, 0],
]

Оттуда это просто вопрос добавления столбцов, простой вызов reduce.

Обновление

Комментарий NinaScholz заставил меня немного переосмыслить, и я понял, что это так же легко сделатьначальный reduce вместо map и создайте только те массивы, которые необходимы.Это изменение должно быть более эффективным:

const spread = arr => arr.reduce(
  (a, n, i) => n == 0 
    ? a 
    : a.concat([arr.map((_, j) => Math.max(n - Math.abs(j - i), 0))]),
  []
).reduce((as, bs) => as.map((a, i) => a + bs[i]))

console.log(...spread([0, 0, 2, 0, 0]))             //~> [0, 1, 2, 1, 0]
console.log(...spread([3, 0, 0, 0]))                //~> [3, 2, 1, 0]
console.log(...spread([0, 0, 0, 3, 0, 2, 0]))       //~> [0, 1, 2, 3, 3, 3, 1]
console.log(...spread([0, 0, 0, 4, 0, 0, 0]))       //~> [1, 2, 3, 4, 3, 2, 1]
console.log(...spread([0, 0, 0, 0, 4, 0, 0, 3, 0])) //~> [0, 1, 2, 3, 4, 4, 4, 4, 2]

С этим изменением промежуточный результат (между двумя reduce вызовами сейчас) будет состоять только из

[
  [0, 1, 2, 3, 4, 3, 2, 1, 0],
  [0, 0, 0, 0, 0, 1, 2, 3, 2],
]

Обновление 2

Видя это снова, я понимаю, что последнее изменение не зашло достаточно далеко.Мы можем исключить все промежуточные массивы, кроме одного, используемого как reduce аккумулятор, просто добавляя к текущему значению по ходу работы.

Вот, что я надеюсь, это моя окончательная версия:

const spread = arr => arr.reduce(
  (a, n, i) => n == 0 
    ? a 
    : arr.map((_, j) => a[j] + Math.max(n - Math.abs(j - i), 0)),
  Array(arr.length).fill(0)
)


console.log(...spread([0, 0, 2, 0, 0]))             //~> [0, 1, 2, 1, 0]
console.log(...spread([3, 0, 0, 0]))                //~> [3, 2, 1, 0]
console.log(...spread([0, 0, 0, 3, 0, 2, 0]))       //~> [0, 1, 2, 3, 3, 3, 1]
console.log(...spread([0, 0, 0, 4, 0, 0, 0]))       //~> [1, 2, 3, 4, 3, 2, 1]
console.log(...spread([0, 0, 0, 0, 4, 0, 0, 3, 0])) //~> [0, 1, 2, 3, 4, 4, 4, 4, 2

У него нет промежуточных структур данных, кроме этого аккумулятора.Это делает только необходимую арифметику.AFAICT, это настолько эффективно, насколько это возможно, по модулю работы с reduce, а не примитивным for -loop.Хотелось бы знать, если я что-то упустил.

1 голос
/ 30 марта 2019

В три этапа: 1. Разобрать входной массив в массиве массивов, каждый из которых содержит одно ненулевое значение.2. Обработайте каждый из этих тривиальных случаев отдельно.3. Сократите их обратно до одного массива.

(наверняка не оптимальное решение с точки зрения производительности).

const explode = arr => {
   const len = arr.length;

   return arr.map((val, index) => new Array(len)
      .fill(0)
      .map((x, j) => index === j ? val : 0)
   );
}

const pop = arr => {
   const nonZeroIndex = arr.findIndex(x => !!x);
   const nonZeroValue = arr.find(x => !!x);

   return nonZeroIndex !== -1 ?
      arr.map((x, i) => Math.max(0, nonZeroValue - Math.abs(i - nonZeroIndex))) :
      arr;
}

const sum2Arrays = (arrA, arrB) => arrA.map((x, i) => x + arrB[i]);
const sumArrays = arrs => arrs.reduce(sum2Arrays, Array(arrs[0].length).fill(0));

const spread = (arr) => sumArrays(explode(arr).map(pop));

console.log(spread([0, 0, 0, 0, 4, 0, 0, 3, 0]));

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...