JS生成嵌套数组

     $scope.testArray = [
          {'bedNum': '1', 'bedMsg': 'test1'},
          {'bedNum': '2', 'bedMsg': 'test2'},
          {'bedNum': '3', 'bedMsg': 'test3'},
          {'bedNum': '4', 'bedMsg': 'test4'},
          {'bedNum': '5', 'bedMsg': 'test5'},
          {'bedNum': '6', 'bedMsg': 'test6'},
          {'bedNum': '7', 'bedMsg': 'test7'},
          {'bedNum': '8', 'bedMsg': 'test8'},
          {'bedNum': '9', 'bedMsg': 'test9'},
          {'bedNum': '10', 'bedMsg': 'test10'},
          {'bedNum': '11', 'bedMsg': 'test11'},
          {'bedNum': '12', 'bedMsg': 'test12'}
        ];
        
  $scope._inArray = [];
  $scope._outArray=[];
      var i = 0;
      angular.forEach($scope.testArray, function (data, index) {
        if (i < $scope.colsNum) {
          i++;
          $scope._inArray.push(data);
          if ($scope.testArray.length == index + 1) {
            $scope._outArray.push($scope._inArray);
          }
        } else {
          $scope._outArray.push($scope._inArray);
          $scope._inArray = [];
          $scope._inArray.push(data);
          i = 1;
        }
      })

<!---------------分割线--------------->

比如$scope.colsNum=3,生成一个$scope._outArray=[[5],[5],[2]]这样的数组。

这里是想把$scope.testArray生成一个嵌套的数组,这样也能实现,但觉得自己写的太啰嗦了,希望给一个更好的写法。

阅读 7.4k
1 个回答

用 lodash

如果用 lodash,很简单,一个函数就搞定

const _ = require("lodash");
const result = _.chunk(data, colsNum);
console.log(result);

lodash 的 _.chunk() 源码

回答完这个问题之后我突然好奇 lodash 是怎么实现的,所以我去翻了下它的源码,其中最关键的一段是

  while (index < length) {
    result[resIndex++] = baseSlice(array, index, (index += size));
  }

可以看出来,它采用的是 slice 的思想,每次取一段出来放在新数组中。 slice 它调用的 baseSlice()_baseSlice.js 中,对应 _.slice() 方法,,实现的功能和 Array.prototype.slice 一致。

这就有意思了,如果采用这种方式,就有办法使用函数式与法了——见自己写函数的第三个方法。

自己写函数

reduce

当然自己写也可以,之前回答某个问题的时候写过,再写一次,用 reduce 再稍加处理。

主要是保持两个数组,一个是结果数组,一个是当前组数组,不需要 i 变量,因为当前组数组的 length 就能取到数量信息。

function groupByCols(data, cols) {
    const r = data.reduce((r, t) => {
        r.current.push(t);
        if (r.current.length === cols) {
            r.list.push(r.current);
            r.current = [];
        }
        return r;
    }, { list: [], current: [] });

    if (r.current.length) {
        r.list.push(r.current);
    }

    return r.list;
}
const result = groupByCols(data, colsNum);
console.log(result);

forEach

其实 reduce 用在这里优势不明显,因为有最后一步处理,不能直接返回结果。所以用和你的方法类似的 forEach 改写

function groupByCols2(data, cols) {
    const list = [];
    let current = [];
    data.forEach(t => {
        current.push(t);
        if (current.length === cols) {
            list.push(current);
            current = [];
        }
    });
    if (current.length) {
        list.push(current);
    }
    return list;
}

slice + map 实现

为了函数式写法,可能有些计算不太好理解,先看代码

const result = Array.apply(null, {
    length: Math.ceil(data.length / cols)
}).map((x, i) => {
    return data.slice(i * cols, i * cols + cols);
});

Array.apply 是为了生成一个长度为 Math.ceil(data.length / cols) 的数组,这就是循环次数(Math.ceil() 用于保证有余数则进1)。

然后在循环次数内通过 slice() 分段取出来。

用 RxJs

RxJs 用于异步处理数据还是挺方便的,用它的 bufferCount() 解决这种问题

const Rx = require("rxjs");
const out = Rx.Observable.from(data)
    .bufferCount(colsNum)
    .toArray()
    .do(console.log)
    .subscribe();

这种方法适合异步或者 callback 处理(上面 console.log 那里传入的你的数据处理函数。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏