たとえば、次のようなポケモンオブジェクトのリストがあったとして:
[
  { name: 'Eevee', type: 'normal' },
  { name: 'Pidgeot', type: 'normal' },
  { name: 'Pikachu', type: 'electric' },
  { name: 'Raichu', type: 'electric' },
  { name: 'Jigglypuff', type: 'normal' },
  { name: 'Squirtle', type: 'water' },
  { name: 'Golduck', type: 'water' },
  { name: 'Voltorb', type: 'electric' }
]
これをタイプ別にグループ化したリストのリストをつくる関数を考えます。
まず、ポケモンオブジェクトをつくる関数:
const toPokemon = (name, type)=> {
    return {
        name: name,
        type: type};
};
この関数を使って、実験対象となるポケモンリスト生成:
const pokemonlist = [
    toPokemon('Eevee',      'normal'),
    toPokemon('Pidgeot',    'normal'),
    toPokemon('Pikachu',    'electric'),
    toPokemon('Raichu',     'electric'),
    toPokemon('Jigglypuff', 'normal'),
    toPokemon('Squirtle',   'water'),
    toPokemon('Golduck',    'water'),
    toPokemon('Voltorb',    'electric')];
console.log(pokemonlist);
このポケモンリストを先頭から順番に調べて、タイプが同じだったらグループ化する再帰関数を作成:
const toNestedList = (pokemons, acc)=>{
    if(pokemons.length<1){
        return acc;
    }
    else {
        const pokemon = head(pokemons);
        const tailPokemons = tail(pokemons);
        const nestedPokemons = last(acc);
        if( nestedPokemons==null ){
            acc.push([pokemon]);
        }
        else {
            if( nestedPokemons[0].type == pokemon.type ){
                nestedPokemons.push(pokemon);
            }
            else {
                acc.push([pokemon]);
            }
        }
        return toNestedList(tailPokemons, acc);
    }
};
この toNestedList で使用する補助関数 head, tail, last 関数を作成:
const head = (list)=>{
    if(list.length<1){
        return null;
    }
    else {
        return list[0];
    }
};
const tail = (list)=>{
    return list.slice(1);
};
/*
const tail = (list)=>{
    if(list.length<2){
        return [];
    }
    else {
        const newList = [];
        for(var i=1; i<list.length; i++){
            newList.push(list[i]);
        }
        return newList;
    }
};
*/
const last = (list)=>{
    if(list.length<1){
        return null;
    }
    else {
        return list[list.length-1];
    }
};
toNestedList を使ってタイプ別のリストのリストを作成:
const pokemonListListByType = toNestedList(pokemonlist, []);
console.log(pokemonListListByType);
node pokemon.js として実行してみます。
[
  [
    { name: 'Eevee', type: 'normal' },
    { name: 'Pidgeot', type: 'normal' }
  ],
  [
    { name: 'Pikachu', type: 'electric' },
    { name: 'Raichu', type: 'electric' }
  ],
  [ { name: 'Jigglypuff', type: 'normal' } ],
  [
    { name: 'Squirtle', type: 'water' },
    { name: 'Golduck', type: 'water' }
  ],
  [ { name: 'Voltorb', type: 'electric' } ]
]
おっと、それなりにはグループ化できたのですが・・・ 順番にポケモンタイプを調べてサブグループ(ネストされたリスト)をつくるので、 toNestedList に与えるポケモンリストは、事前にタイプ別にソートされている必要がありました。
タイプ別にソートする関数 sortByType を作成:
const sortByType = (pokemons)=>{
    return pokemons.sort( (pokemon0, pokemon1)=>{
        return pokemon0.type.localeCompare(pokemon1.type);
    });
};
localeCompare() とは?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare
これを使って、再度出力してみます。
const pokemonListListByType = toNestedList( sortByType(pokemonlist), []);
console.log(pokemonListListByType);
node pokemon.js として実行:
[
  [
    { name: 'Pikachu', type: 'electric' },
    { name: 'Raichu', type: 'electric' },
    { name: 'Voltorb', type: 'electric' }
  ],
  [
    { name: 'Eevee', type: 'normal' },
    { name: 'Pidgeot', type: 'normal' },
    { name: 'Jigglypuff', type: 'normal' }
  ],
  [
    { name: 'Squirtle', type: 'water' },
    { name: 'Golduck', type: 'water' }
  ]
]
うまくいきました。
pokemon.js:
const toPokemon = (name, type)=> {
    return {
        name: name,
        type: type};
};
const pokemonlist = [
    toPokemon('Eevee',      'normal'),
    toPokemon('Pidgeot',    'normal'),
    toPokemon('Pikachu',    'electric'),
    toPokemon('Raichu',     'electric'),
    toPokemon('Jigglypuff', 'normal'),
    toPokemon('Squirtle',   'water'),
    toPokemon('Golduck',    'water'),
    toPokemon('Voltorb',    'electric')];
console.log(pokemonlist);
const head = (list)=>{
    if(list.length<1){
        return null;
    }
    else {
        return list[0];
    }
};
const tail = (list)=>{
    return list.slice(1);
};
const last = (list)=>{
    if(list.length<1){
        return null;
    }
    else {
        return list[list.length-1];
    }
};
const toNestedList = (pokemons, acc)=>{
    if(pokemons.length<1){
        return acc;
    }
    else {
        const pokemon = head(pokemons);
        const tailPokemons = tail(pokemons);
        const nestedPokemons = last(acc);
        if( nestedPokemons==null ){
            acc.push([pokemon]);
        }
        else {
            if( nestedPokemons[0].type == pokemon.type ){
                nestedPokemons.push(pokemon);
            }
            else {
                acc.push([pokemon]);
            }
        }
        return toNestedList(tailPokemons, acc);
    }
};
const sortByType = (pokemons)=>{
    return pokemons.sort( (pokemon0, pokemon1)=>{
        return pokemon0.type.localeCompare(pokemon1.type);
    });
};
//const pokemonListListByType = toNestedList(pokemonlist, []);
const pokemonListListByType = toNestedList( sortByType(pokemonlist), []);
console.log(pokemonListListByType);