使用Javascript将连续的元素分组在一起

Grouping consecutive elements together using Javascript

本文关键字:在一起 元素 Javascript 连续 使用      更新时间:2023-09-26

我有一个元素数组,像这样:

messages[i],其中messages[i]仅对i的某些值存在。例如,messages[0]messages[2]可能存在,但messages[1]不存在。

现在我想将具有连续索引的元素分组在一起,例如,如果存在消息的索引为:

2, 3, 4, 5, 8, 9, 12, 13, 14, 15, 16, 17, 20

我想这样分组:

2, 3, 4, 5

8, 9

12, 13, 14, 15, 16, 17

20

使用Javascript实现这一目标的有效方法是什么?

编辑:

for (i = 0; i < messages.length; i++) {
   if (messages[i].from_user_id == current_user_id) {
   // group the continuous messages together
      } else {
  //group these continuous messages together
   }
}

您可以使用计数器变量,该变量必须递增,并且索引和连续元素之间的差值相同,将它们分组在临时数组中。如果两个连续的数组元素的差值不同,则必须将临时元素移到result中,并且必须为临时数组分配一个新的数组对象。

var array = [2, 3, 4, 5, 8, 9, 12, 13, 14, 15, 16, 17, 20];
var result = [], temp = [], difference;
for (var i = 0; i < array.length; i += 1) {
    if (difference !== (array[i] - i)) {
        if (difference !== undefined) {
            result.push(temp);
            temp = [];
        }
        difference = array[i] - i;
    }
    temp.push(array[i]);
}
if (temp.length) {
    result.push(temp);
}
console.log(result);
# [ [ 2, 3, 4, 5 ], [ 8, 9 ], [ 12, 13, 14, 15, 16, 17 ], [ 20 ] ]

给定:

var data = [ undefined, undefined, 2, 3, 4, 5,
             undefined,undefined, 8, 9,
             undefined, undefined, 12, 13, 14, 15, 16, 17,
             undefined, undefined, 20];

(或者几乎相等的数组,其中undefined元素根本不存在,但定义的元素具有与上面相同的索引),reduce调用将返回一个二维数组,其中每个顶层元素是原始数组的内容,按连续定义的项分组:

var r = data.reduce(function(a, b, i, v) {
    if (b !== undefined) {              // ignore undefined entries
        if (v[i - 1] === undefined) {   // if this is the start of a new run
            a.push([]);                 // then create a new subarray
        }
        a[a.length - 1].push(b);        // append current value to subarray
    }
    return a;                           // return state for next iteration
}, []);                                 // initial top-level array

[[ 2, 3, 4, 5], [8, 9], [12, 13, 14, 15, 16, 17], [20]]

注意:这也可以使用.forEach调用来编写,但我喜欢.reduce,因为它不需要临时变量-所有状态都封装在函数参数中。

我会遍历列表,如果在messages[i]找到元素,则将i添加到min列表中。然后,一旦在messages[j]处找不到元素,就把j放到最大值列表中。

那么您将有两个列表(或者一个,如果您使用容器,我可能会这样做),其中包含组的开始和停止索引。

另一种方法是这样的。我使用了一个叫做lodash的库来操作数组。

基本上我是按升序对数组进行排序。然后对于每一次增量,我将当前元素存储到一个临时数组中如果数组的最后一个值与当前元素的值是顺序的,那么比较它们的最后一个值如果它们不是顺序的,我将临时数组的值压入结果数组中,以此类推。如果循环结束,我就把临时数组的值压入结果数组。

var _ = require('lodash');
var arr = [2, 3, 4, 5, 8, 9, 12, 13, 14, 15, 16, 17, 20];
arr = _.sortBy(arr, function (o) {
    return o;
});
var tmp = [];
var res = [];
for (var i = 0; i < arr.length; i++) {
    if (tmp.length === 0) {
        tmp.push(arr[i]);
    }
    else {
        var lastEl = _.last(tmp);
        if ((lastEl + 1) === arr[i]) {
            tmp.push(arr[i]);
        }
        else {
            res.push(tmp);
            tmp = [];
            tmp.push(arr[i]);
        }
        if (i === (arr.length - 1)) {
            res.push(tmp);
            tmp = [];
        }
    }
}
// Outputs: [ [ 2, 3, 4, 5 ], [ 8, 9 ], [ 12, 13, 14, 15, 16, 17 ], [ 20 ] ]

const cluster = (arr, tmp = [], result = []) => 
    (result = arr.reduce((acc, c, i) => 
        (!tmp.length || c === (arr[i-1]+1)
            ? (tmp.push(c), acc) 
            : (acc.push(tmp), tmp = [c], acc))
            , []), tmp.length ? (result.push(tmp), result) : result)
console.log(cluster([2, 3, 4, 5, 8, 9, 12, 13, 14, 15, 16, 17, 20]))