如何使用Javascript计算数组中的相邻数字?

Posted

技术标签:

【中文标题】如何使用Javascript计算数组中的相邻数字?【英文标题】:How to count neighboring numbers in an array using Javascript? 【发布时间】:2021-03-15 19:15:31 【问题描述】:

我的输入是这样的数组:

[7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7]

我想将这些数字组合在一起并将它们相加,但要按邻居,而不是按数组中的总数。所以输出将是:

['7:4', '4:2', '5:3', 1, 9, 2, '7:2']

我使用reduce 尝试了几种不同的方法,并且很接近,但使用内置的 javascript 方法我最终计算了数组中的 ALL,而不是邻居。

const firstArray = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7];
const masterArray = [];

const unique = new Set (numberArray); // Set 7, 4, 5, 1, 9, 2, 7
unique.forEach(u => 
  masterArray.push(numberArray.filter(e => e === u));
);

console.log(masterArray);

在这里使用 Set 显然是错误的,因为它会获取唯一值并计算它们,但我只想通过邻居来做。所以我想我应该使用reduce,但我遇到了同样的问题。

【问题讨论】:

【参考方案1】:

var test = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7];

console.log(
  test.reduce((acc, element) => 
    if (acc.length && acc[acc.length - 1].key == element) 
      acc[acc.length - 1].count++;
     else 
      acc.push( key: element, count: 1 );
    
    
    return acc;
  , []).map(element => `$element.key:$element.count`)
);

所以逻辑首先将数字减少到一个数组,跟踪最后一个键和计数。只要密钥相同,计数就会增加。一旦密钥发生变化,就会推送一个新对象以开始下一次运行。在reduce完成后,执行一个map,将key和counts转换成想要的字符串。

【讨论】:

完美。我在 .map 部分添加了一个检查以单独保留单个数字: element => element.count !== 1 ? $element.key:$element.count : element.key) 并且效果很好。【参考方案2】:

您需要跟踪在持久变量中迭代的最后一个数字,以及最后一个递增数字的出现次数:

const arr = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7];
let lastNum = arr[0];
let count = 0;
const results = [];
const doPush = () => 
  results.push(
    count === 1
      ? lastNum
      : `$lastNum:$count`
  );
;
for (const num of arr) 
  if (num !== lastNum) 
    doPush();
    lastNum = num;
    count = 1;
   else count++;

doPush();

console.log(results);

【讨论】:

这看起来像我会用 C++ 解决它,但这在 javascript 中也更快吗?还有什么时候有一百万个数字? (显示完全缺乏 javascript 经验) 我不知道。一方面,我认为像 JS 这样的高级语言基本上比低级语言慢一些如果低级语言针对性能进行了优化。另一方面,现在的 JS 编译器在优化方面相当不错,因此差异可能不会那么大。与往常一样,为了提高性能,请使用实际输入自行运行一些测试以找出答案。【参考方案3】:

您可以通过查看实际值之前的索引的最后一个值来减少数组。

const 
    array = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7],
    result = array.reduce((r, value, i,  [i - 1]: last ) => 
        let count = 0;
        if (last === value) count = (+r.pop().toString().split(':')[1] || 0) + 1;
        return [...r, count ? `$value:$count`: value];
    , []);

console.log(result);

【讨论】:

[i - 1]: last 这怎么可能? 这是解构,它声明了一个last变量,其中包含第4个参数(包含数组)的i - 1属性的值【参考方案4】:

这里有一个解决方案,使用递归函数将邻居分组,然后Array.prototype.map()用冒号格式化:

const arr = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7],
  output = (function groupNeighbors([first, ...rest], output = [], last) 
    last === first ? output[output.length - 1].push(first) : output.push([first]); 
    return rest.length ? groupNeighbors(rest, output, first) : output;
  )(arr).map(( [0]: num, length ) => length > 1 ? [num, length].join(':') : num);

console.log(output);

由于它使用递归,它在输入数组长度方面受到限制,您可以在此处找到每个浏览器的堆栈大小限制:Browser Javascript Stack size limit

Array.prototype.reduce() 的变体(略短,无递归,输入长度不受限制):

const arr = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7],
  output = arr
    .reduce(
      (acc, cur, i,  [i - 1]: last ) =>
        (cur === last ? acc[acc.length - 1].push(cur) : acc.push([cur])) && acc,
      []
    )
    .map(( [0]: num, length ) => length > 1 ? [num, length].join(':') : num);

console.log(output);

【讨论】:

【参考方案5】:

是的,这里的正确选择是reduce

const countDuplicatesQuantity = (arr) => 
    const duplicatesObj = arr.reduce((duplicates, item) => 
        duplicates[item] = duplicates[item] ? duplicates[item] + 1 : 1;

        return duplicates;
    , );

    return Object.keys(duplicatesObj).map(
        (key) => `$key:$duplicatesObj[key]`,
    );
;

【讨论】:

【参考方案6】:

你想减少,两次怎么样? :)(我不知道我是否在这里做了一些愚蠢的事情。)

首先reduce找到数组中值变化的地方,第二个使用它来构建新数组。

const firstArray = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7];

const masterArray = firstArray
  .reduce((acc, v, i, all) => all[i + 1] !== v ? acc.concat(i) : acc, [])
  .reduce(
    (acc, v, i, all) => 
      const range = v - (i === 0 ? -1 : all[i - 1]);
      return acc.concat(range > 1 ? firstArray[v] + ':' + range : firstArray[v]);
    , []
  );
  

console.log(masterArray);

【讨论】:

【参考方案7】:

使用array.reduce:

const firstArray = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7];
var newArray = [];
var count = 0;
firstArray.reduce((acc, cur, index) => 
  if (acc == cur) 
    count++;
  
  if (acc != cur || index+1 == firstArray.length) 
    newArray.push(acc + ":" + count);
    count=1
  
  return cur;
)
console.log(newArray);

【讨论】:

【参考方案8】:

我的方式......我觉得可以“更简单”

const firstArray = [7, 7, 7, 7, 4, 4, 5, 5, 5, 1, 9, 2, 7, 7];
 
const result = firstArray.reduceRight((r,v)=>
  
  let [n,c] = !r.length ? [-v,0] : isNaN(r[0]) ? r[0].split(':') : [r[0],1]
  if (n==v) r[0] = `$n:$++c`
  else      r.unshift(v)
  return r
  ,[])
  
console.log( JSON.stringify(result) )
//  [ "7:4", "4:2", "5:3", 1, 9, 2, "7:2" ]
.as-console-wrapper  max-height: 100% !important; top: 0; 

【讨论】:

@stonerose036 我觉得可以“更简单”

以上是关于如何使用Javascript计算数组中的相邻数字?的主要内容,如果未能解决你的问题,请参考以下文章

#yyds干货盘点# 动态规划专题:删除相邻数字的最大分数

Javascript - 如何将数组中的数字转换为字符串并使用 If 语句

用JavaScript实现排序算法

三元运算符如何比较 JavaScript 中的字符和数字?

sas如何计算相邻观测的差值

检查javascript数组中的数字索引[关闭]