在一个数字序列中,如何计算一个数字出现多少次,即该值恰好比前一个数字的值小一?

How does one, within a sequence of digits, count how many times a digit appears thats value is exactly one less than the previous digit's one?

代码:

function OneDecremented(num) { 
  num = num.toString()
  var count = 0

  for(i = 1; i < num.length; i++) {
    if(num[i - 1] - num[i] === 1){
      count++
    }
  }
  return count

}
console.log(OneDecremented(9876541110))

所以我很难理解两件事:

  1. i和num[i]有什么区别
  2. 我不明白 if 语句中的计算是如何进行的,有人可以分解一下吗?

抱歉,如果这些问题听起来太傻了,我是 JS 的新手,无法真正理解算术计算。谢谢你的时间。

what's the difference between i and num[i]

i 是迭代键,即 0、1、2 等,因为字符串化数字中有尽可能多的字符。 num[i] 是字符串中索引 i 处的字符,即 num[i] 其中 i 是 0 == 9 (字符串中索引 0 处的字符).

I don't understand how the calculation is happening inside the if statement, could someone break it down?

表示:如果计算字符串索引i-1处的数字,减去当前正在考虑的数字(字符串中索引i处)减去1,则递增count.

实际用到的数字一步一步来:

  • 9 - 没有前一个字符;计算 (undefined - 9) 不等于 1
  • 8 - 前一个字符是 9; (9 - 8) == 1;递增 count
  • 7 - 同上
  • 6 - 同上
  • 5 - 同上
  • 4 - 同上
  • 1 - 前一个字符是 4;计算 (4 - 1) 不等于 1
  • 1 - 前一个字符为 1;计算 (1 - 1) 不等于 1
  • 1 - 同上
  • 0 - 前一个字符为 1; (1 - 0) == 1;递增 count

该代码写得不好有几个原因,但最重要的是,它泄漏了全局的 i 引用,所以,让我们从一个更好的版本开始:

function OneDecremented(num) {
  var str = num.toString();
  var count = 0;
  for(var i = 1; i < str.length; i++) {
    if(str[i - 1] - str[i] === 1)
      count++;
  }
  return count;
}

字符串,在现代JS中,可以像数组一样访问,索引returns是index位置的char:

if(str[i - 1] - str[i] === 1)
// is the same as
if ((str.charAt(i - 1) - str.charAt(i)) === 1)

一旦检索到每个字符,代码就会执行隐式的“字符到数字”转换,这要归功于 - 运算符,但如果它是 + 相反,它会将两个字符连接成字符串(所以,要小心)。

明确总是更好,但如果您知道 - 的工作原理,它就可以完成这项任务。

循环从 1 开始,它检查 i - 1 处的字符,即第一次迭代中索引 0 处的字符,减去当前字符,是1,表示当前字符 比前一个字符少

在这种情况下,计数器会求和。

Andrea 和 Mitya 已经搞定了。

下一步可能是切换到 first class based approach like using a specific Array method such as reduce

这种方法如果实施得当,通常会改进 readability/maintainability 代码并实现更好的代码重用。

对于 OP 提供的示例,可以编写两个函数,即获取计数的实际方法和上面提到的第一个 class reducer 功能。由于 reduce 是处理数组的标准方式,因此 reducer/callback 的参数优先级也已明确指定 ...

[/* ... */].reduce(function(accumulator, currentValue, currentIndex, currentlyProcessedArray) {

  // implement reducer/aggregation/accumulator logic here.

  // the return value serves as the
  // new `accumulator` value within
  // the next iteration step.

  // thus, always return something! ... e.g ...

  return (accumulator + currentValue); 
});

function aggregatePrecursorAndDecrementedSuccessorCount(count, char, idx, arr) {

  const precursorValue = Number(arr[idx - 1]);
  const incrementedCurrentValue = (Number(char) + 1);
  const isValidCount = (precursorValue === incrementedCurrentValue);

  return (count + (isValidCount ? 1 : 0));
//return (count + Number(isValidCount)); // cast boolean value to either 1 or 0.
}

function getPrecursorAndDecrementedSuccessorCount(int) {
  return String(int) // - assure/typecast always a/into string value.
    .split('')       // - split string value into an array of single characters.
    .reduce(aggregatePrecursorAndDecrementedSuccessorCount, 0);
}

console.log(getPrecursorAndDecrementedSuccessorCount(9876541110));
.as-console-wrapper { min-height: 100%!important; top: 0; }