Search code examples
javascriptarraysmultidimensional-arrayarraylist

How to split/create an array on repeated duplicated key


const test = [{a:1},{b:2},{c:3},{d:4},{a:5},{b:6},{c:7},{a:8},{c:9}]

Need output like below, On repeat of key "a", need to create new array till the same key repeat

[{a:1},{b:2},{c:3},{d:4}]
[{a:5},{b:6},{c:7}]
[{a:8},{c:9}]

Solution

  • For the best performance don't mutate the source and don't push by 1 element, rather slice:

    const test = [{a:1},{b:2},{c:3},{d:4},{a:5},{b:6},{c:7},{a:8},{c:9}];
    
    let result = [], prev = 0, i = 0, [sc] = Object.keys(test[0]);
    while(++i < test.length) sc in test[i] && result.push(test.slice(prev, prev = i));
    result.push(test.slice(prev));
    
    result.forEach(item => console.log(JSON.stringify(item)));

    And a benchmark:

    ` Chrome/125
    -------------------------------------------------------
    Alexander       ■ 1.00x | x10000000 570 579 608 626 627
    Siva KV           1.93x |  x1000000 110 114 120 128 134
    Roko C. Buljan    2.77x |  x1000000 158 159 166 169 170
    ------------------------------------------------------- `
    

    Open in the playground

    <script benchmark data-count="5000000">
    const test = [{a:1},{b:2},{c:3},{d:4},{a:5},{b:6},{c:7},{a:8},{c:9}];
    
    // @benchmark Roko C. Buljan
    [...test].reduceRight((acc, ob, i, ref) => 
      (ob.hasOwnProperty("a") && acc.unshift(ref.splice(i)), acc)
    , []);
    
    // @benchmark Siva KV
    {
    const result = [];
    let row = [];
    test.forEach((item) => {
      const key = Object.keys(item)[0];
      if (key === "a") {
        if (row.length > 0) {
          result.push(row);
        }
        row = [item];
      } else {
        row.push(item);
      }
    });
    if (row.length > 0) {
      result.push(row);
    }
    result;
    }
    
    // @benchmark Alexander
    let result = [], prev = 0, i = 0, sc = Object.keys(test[0])[0];
    while(++i < test.length) sc in test[i] && result.push(test.slice(prev, prev = i));
    result.push(test.slice(prev));
    result;
    </script>
    <script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>