Javascript - Подсчет элементов массива методом уменьшения до тех пор, пока не появится указанное значение c, не дает правильного вывода - PullRequest
0 голосов
/ 29 мая 2020
const arr = [5,6,0,7,8];
const sum = (arr,num) => arr.reduce((total)=>(num==0 ? total : total+num), 0) 
console.log(sum(arr, 0))

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

Ответы [ 4 ]

1 голос
/ 29 мая 2020

Это неудобно делать в .reduce, потому что он проходит через весь массив . Если мы сделаем наивную реализацию, вы увидите проблему:

const arr = [5,6,0,7,8];
const sum = (arr,num) => arr.reduce((total, x)=>(num==x ? total : total+x), 0) 
console.log(sum(arr, 0))

Теперь мы делаем проверку правильно - num==x вернет true, когда x равно нулю (значение num). Однако результат неверен, потому что он возвращает только true один раз , но при любой другой итерации он все равно true. И вот то же самое с дополнительным журналом, описывающим каждый шаг процесса:

const arr = [5,6,0,7,8];
const sum = (arr,num) => arr.reduce((total, x)=> {
  const boolCheck = num==x;
  const result = boolCheck ? total : total+x;
  console.log(
`total: ${total}
num: ${num}
x: ${x}
boolCheck: ${boolCheck}
result: ${result}`);

    return result;
  }, 0) 
console.log(sum(arr, 0))

Итак, вам нужно добавить некоторый флаг, который сохраняется между итерациями, чтобы он не терялся.

Один из вариантов - иметь внешний флаг которые вы меняете в обратном вызове reduce:

const arr = [5,6,0,7,8];
const sum = (arr,num) => {
  let finished = false;
  return arr.reduce((total, x) => {
    if(x === num)
      finished = true;
      
    return finished ? total : total+x;
  }, 0)
}
console.log(sum(arr, 0))

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

const arr = [5,6,0,7,8];
const sum = (arr,num) => {
  return arr.reduce(({total, finished}, x) => {
    if(x === num)
      finished = true;

    total = finished ? total : total+x;

    return {total, finished};
  }, {total: 0, finished: false})
  .total
}
console.log(sum(arr, 0))

Если вы хотите использовать reduce, но можете использовать другие методы, то вы можете использовать Array#indexOf, чтобы найти первый экземпляр значения и Array#slice массив, содержащий любое значение вплоть до целевого значения:

const arr = [5,6,0,7,8];
const sum = (arr,num) => {
  const endIndex = arr.indexOf(num);
  
  return arr.slice(0, endIndex)
    .reduce((total, x)=> total+x, 0)
}
console.log(sum(arr, 0))

Или в виде одного связанного выражения:

const arr = [5,6,0,7,8];
const sum = (arr,num) => arr
  .slice(0, arr.indexOf(num))
  .reduce((total, x)=> total+x, 0);

console.log(sum(arr, 0))

Другие библиотеки могут иметь операцию takeUntil или takeWhile, которая даже ближе к тому, что вы хотите - она ​​дает вам массив из начиная с до заданного значения или условия. Затем вы можете уменьшить результат этого.

Вот пример этого с использованием Lodash#takeWhile

Используя здесь цепочку, Loda sh выполнит ленивую оценку , поэтому он будет go пройти через массив только один раз, вместо того, чтобы сканировать один раз, чтобы найти конечный индекс, и снова пройти через массив для его суммирования.

const arr = [5,6,0,7,8];
const sum = (arr,num) => _(arr)
  .takeWhile(x => x !== num)
  .reduce((total, x)=>total+x, 0)

console.log(sum(arr, 0))
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>

В качестве примечания, если вы используете , используя Loda sh, то вы также можете использовать _.sum(). Выше я не просто проиллюстрировал, как выглядит generi c takeUntil / takeWhile.

const arr = [5, 6, 0, 7, 8];
const sum = (arr, num) => _(arr)
  .takeWhile(x => x !== num)
  .sum()

console.log(sum(arr, 0))
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>
1 голос
/ 29 мая 2020

Поскольку вам нужно прекратить суммирование значений на полпути через массив, это может быть проще всего реализовать, используя for l oop:

const arr = [5, 6, 0, 7, 8];
const num = 0;

let sum = 0;
for (let i = 0; i < arr.length; i++) {
  if (arr[i] == num) break;
  sum += arr[i];
}
console.log(sum);

Если вы хотите использовать reduce, вам нужно сохранить флаг, который говорит, видели ли вы значение num, чтобы вы могли прекратить добавлять значения из массива :

const arr = [5, 6, 0, 7, 8];

const sum = (arr, num) => {
  let seen = false;
  return arr.reduce((c, v) => {
    if (seen || v == num) {
      seen = true;
      return c;
    }
    return c + v;
  }, 0);
}

console.log(sum(arr, 0));
console.log(sum(arr, 8));
0 голосов
/ 29 мая 2020

Вам нужны круглые скобки для выполнения функции ()

sum(arr, 0)

Без круглых скобок вы сохраняете ссылку на функцию в переменной

0 голосов
/ 29 мая 2020

назовите его так:

console.log(sum(arr, 0)());
...