skip to Main Content

I’ve got an array of objects that each carry a columnSpan property with a numeric value between 1 and 16.

[
  {
    "columnSpan": 4,
    "id": "DatoCmsEntry-MaixsOYtSwS7mloD59Rvng"
  },
  {
    "columnSpan": 4,
    "id": "DatoCmsEntry-fEuNly9-QFiRh4DoUZ-Y_w"
  },
  {
    "columnSpan": 2,
    "id": "DatoCmsEntry-HsAgXDMHQkSXS_4lKSGfGA"
  },
  {
    "columnSpan": 2,
    "id": "DatoCmsEntry-BM-fSBruSM67IFzCrBSLBg"
  },
  {
    "columnSpan": 3,
    "id": "DatoCmsEntry-JPushhKGSBCwR_uWcwIFSw"
  },
  {
    "columnSpan": 3,
    "id": "DatoCmsEntry-Q0sfjP9ZQZSDZZVP_sI9ew"
  },
  {
    "columnSpan": 2,
    "id": "DatoCmsEntry-CdVhbQENQ4ib2z4w3wc20Q"
  },
  {
    "columnSpan": 2,
    "id": "DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ"
  }
]

I need to split this array up into a multidimensional array where each top-level item represents a collection of records where the total columnSpan is 16 or less, keeping the original order, like this:

[
  [
    {
      "columnSpan": 4,
      "id": "DatoCmsEntry-MaixsOYtSwS7mloD59Rvng"
    },
    {
      "columnSpan": 4,
      "id": "DatoCmsEntry-fEuNly9-QFiRh4DoUZ-Y_w"
    },
    {
      "columnSpan": 2,
      "id": "DatoCmsEntry-HsAgXDMHQkSXS_4lKSGfGA"
    },
    {
      "columnSpan": 2,
      "id": "DatoCmsEntry-BM-fSBruSM67IFzCrBSLBg"
    },
    {
      "columnSpan": 3,
      "id": "DatoCmsEntry-JPushhKGSBCwR_uWcwIFSw"
    }
  ],
  [
    {
      "columnSpan": 3,
      "id": "DatoCmsEntry-Q0sfjP9ZQZSDZZVP_sI9ew"
    },
    {
      "columnSpan": 2,
      "id": "DatoCmsEntry-CdVhbQENQ4ib2z4w3wc20Q"
    },
    {
      "columnSpan": 2,
      "id": "DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ"
    }
  ]
]

Suggestions on ways to pull this off?

3

Answers


  1. you can pull this off by keeping 2 extra variables to track the current chunk and the current total. Anyway you need an array to store the chunks. Then it is just a loop. I keep adding to the current chunk until it is less than or equal to 16, else I’m resetting the current chunked and total variables. Also I directly do currentChunk = [item] currentTotal = item.columnSpan instead of currentChunk = [] & currentChunk.push(item) and currentTotal = 0 & currentTotal += item.columnSpan
    The final if check is needed to add the final chunk

    const data  = [ { "columnSpan": 4, "id": "DatoCmsEntry-MaixsOYtSwS7mloD59Rvng" }, { "columnSpan": 4, "id": "DatoCmsEntry-fEuNly9-QFiRh4DoUZ-Y_w" }, { "columnSpan": 2, "id": "DatoCmsEntry-HsAgXDMHQkSXS_4lKSGfGA" }, { "columnSpan": 2, "id": "DatoCmsEntry-BM-fSBruSM67IFzCrBSLBg" }, { "columnSpan": 3, "id": "DatoCmsEntry-JPushhKGSBCwR_uWcwIFSw" }, { "columnSpan": 3, "id": "DatoCmsEntry-Q0sfjP9ZQZSDZZVP_sI9ew" }, { "columnSpan": 2, "id": "DatoCmsEntry-CdVhbQENQ4ib2z4w3wc20Q" }, { "columnSpan": 2, "id": "DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ" } ]
    
    const chunked = []
    let currentChunk = []
    let currentTotal = 0
    
    for (const item of data) {
      if (currentTotal + item.columnSpan <= 16) {
        currentChunk.push(item)
        currentTotal += item.columnSpan
      } else {
        chunked.push(currentChunk)
        currentChunk = [item]
        currentTotal = item.columnSpan
      }
    }
    
    if (currentChunk.length > 0) {
      chunked.push(currentChunk)
    }
    
    console.log(chunked)

    or same thing using a reduce

    const data  = [ { "columnSpan": 4, "id": "DatoCmsEntry-MaixsOYtSwS7mloD59Rvng" }, { "columnSpan": 4, "id": "DatoCmsEntry-fEuNly9-QFiRh4DoUZ-Y_w" }, { "columnSpan": 2, "id": "DatoCmsEntry-HsAgXDMHQkSXS_4lKSGfGA" }, { "columnSpan": 2, "id": "DatoCmsEntry-BM-fSBruSM67IFzCrBSLBg" }, { "columnSpan": 3, "id": "DatoCmsEntry-JPushhKGSBCwR_uWcwIFSw" }, { "columnSpan": 3, "id": "DatoCmsEntry-Q0sfjP9ZQZSDZZVP_sI9ew" }, { "columnSpan": 2, "id": "DatoCmsEntry-CdVhbQENQ4ib2z4w3wc20Q" }, { "columnSpan": 2, "id": "DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ" } ]
    
    const {chunked, currentChunk} = data.reduce((acc, curr) => {
      if (acc.currentTotal + curr.columnSpan <= 16) {
        acc.currentChunk.push(curr)
        acc.currentTotal += curr.columnSpan
      } else {
        acc.chunked.push(acc.currentChunk)
        acc.currentChunk = [curr]
        acc.currentTotal = curr.columnSpan
      }
      return acc
    }, { chunked: [], currentChunk: [], currentTotal: 0 })
    
    if (currentChunk.length) {
      chunked.push(currentChunk)
    }
    
    console.log(chunked)
    Login or Signup to reply.
  2. I will suggest an option with the use of reduce. The script goes sequentially through the array and counts ColumnSpan. If no more than 16, it adds to the current array, if it exceeds, it adds to the next one, and so on.

    const init = [
      {"columnSpan": 4, "id": "DatoCmsEntry-MaixsOYtSwS7mloD59Rvng"},
      {"columnSpan": 4, "id": "DatoCmsEntry-fEuNly9-QFiRh4DoUZ-Y_w"},
      {"columnSpan": 2, "id": "DatoCmsEntry-HsAgXDMHQkSXS_4lKSGfGA"},
      {"columnSpan": 2, "id": "DatoCmsEntry-BM-fSBruSM67IFzCrBSLBg"},
      {"columnSpan": 3, "id": "DatoCmsEntry-JPushhKGSBCwR_uWcwIFSw"},
      {"columnSpan": 3, "id": "DatoCmsEntry-Q0sfjP9ZQZSDZZVP_sI9ew"},
      {"columnSpan": 2, "id": "DatoCmsEntry-CdVhbQENQ4ib2z4w3wc20Q"},
      {"columnSpan": 2, "id": "DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ"},
      {"columnSpan": 4, "id": "DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ"},
      {"columnSpan": 5, "id": "DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ"},
      {"columnSpan": 8, "id": "DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ"},
      {"columnSpan": 8, "id": "DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ"},
    ];
    
    function groupBySum(init) {
      const group = init.reduce((acc, item) => {
        const summa = acc.sum + item.columnSpan;
        if (summa <= 16) {
          acc.delta.push(item);
          acc.sum = summa;
        } else {
          acc.sum = item.columnSpan;
          acc.result.push(acc.delta);
          acc.delta = [];
          acc.delta.push(item)
        }
        return acc;
      }, { sum: 0, result: [], delta: []});
    
      group.result.push(group.delta);
    
      return group.result;
    }
    
    console.log(groupBySum(init))

    OR

    const init = [
      {"columnSpan": 4, "id": "DatoCmsEntry-MaixsOYtSwS7mloD59Rvng"},
      {"columnSpan": 4, "id": "DatoCmsEntry-fEuNly9-QFiRh4DoUZ-Y_w"},
      {"columnSpan": 2, "id": "DatoCmsEntry-HsAgXDMHQkSXS_4lKSGfGA"},
      {"columnSpan": 2, "id": "DatoCmsEntry-BM-fSBruSM67IFzCrBSLBg"},
      {"columnSpan": 3, "id": "DatoCmsEntry-JPushhKGSBCwR_uWcwIFSw"},
      {"columnSpan": 3, "id": "DatoCmsEntry-Q0sfjP9ZQZSDZZVP_sI9ew"},
      {"columnSpan": 2, "id": "DatoCmsEntry-CdVhbQENQ4ib2z4w3wc20Q"},
      {"columnSpan": 2, "id": "DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ"},
      {"columnSpan": 4, "id": "DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ"},
      {"columnSpan": 5, "id": "DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ"},
      {"columnSpan": 8, "id": "DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ"},
      {"columnSpan": 8, "id": "DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ"},
    ];
    
    function splitBySpan(arr) {
      let acc = 0;
      let slot = 0;
      const result = [[]];
      arr.forEach(item => {
        if (acc + item.columnSpan <= 16) {
          acc += item.columnSpan;
          result[slot].push(item);
        } else {
          acc = item.columnSpan;
          slot++;
          result.push([item])
        }
      })
      return result;
    }
    console.log(splitBySpan(init));
    Login or Signup to reply.
  3. Reduce the array. In the reducer start by checking if a new chunk should be added. Always add the current item to the last chunk.

    const fn = (arr, max) => arr.reduce((acc, o) => {
      // add a new chunk and reset sum if no chunks, or next item would go over the max
      if(!acc.res.length || acc.sum + o.columnSpan > max) {
        acc.sum = 0
        acc.res.push([])
      }
    
      acc.res.at(-1).push(o) // push current item to last chunk
    
      acc.sum += o.columnSpan // add current columnSpan to sum
    
      return acc
    }, { res: [], sum: 0 }).res
    
    const data = [{"columnSpan":4,"id":"DatoCmsEntry-MaixsOYtSwS7mloD59Rvng"},{"columnSpan":4,"id":"DatoCmsEntry-fEuNly9-QFiRh4DoUZ-Y_w"},{"columnSpan":2,"id":"DatoCmsEntry-HsAgXDMHQkSXS_4lKSGfGA"},{"columnSpan":2,"id":"DatoCmsEntry-BM-fSBruSM67IFzCrBSLBg"},{"columnSpan":3,"id":"DatoCmsEntry-JPushhKGSBCwR_uWcwIFSw"},{"columnSpan":3,"id":"DatoCmsEntry-Q0sfjP9ZQZSDZZVP_sI9ew"},{"columnSpan":2,"id":"DatoCmsEntry-CdVhbQENQ4ib2z4w3wc20Q"},{"columnSpan":2,"id":"DatoCmsEntry-Fn2U_0CuQDiBEOZLmS3ovQ"}]
    
    const result = fn(data, 16)
    
    console.log(result)
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search