5
\$\begingroup\$

My Objective is to create a fixed column array object of size 4 columns so that I can form a 2d array in the following format which I can use to print to a pdf later. The solution is working fine. But need help in figuring out if there is a better way to implement this.

let input = [{
 id:123,
 quantity: 4,
 value: "xxxx"
},
{
 id:234,
 quantity: 11,
 value: "xxxx"
},
{
 id:345,
 quantity: 1,
 value: "xxxx"
}]
output = [
 [ objHeader, objValue, objValue, objValue ],
 [ objValue, null, null, null ],
 [ objHeader1, objValue1, objValue1, objValue1 ],
 [ objValue1, objValue1, objValue1, objValue1 ],
 [ objValue1, objValue1, objValue1, objValue1 ],
 [ objHeader2, objValue2, null, null ]
]
where objHeader = {
 id:123,
 header:true,
 quantity: 4,
 value: xxxx
}
objValue = {
 id:123,
 header:false,
 quantity: 4,
 value: xxxx
}

objValue is basically input[0].id repeated by the factor present in quantity

objValue1 is input[1].id repeated by the factor present in quantity and so on

Code that is working now

let input = [
 {
 id: 123,
 quantity: 4,
 value: "x1xxx"
 },
 {
 id: 234,
 quantity: 11,
 value: "x2xxx"
 },
 {
 id: 345,
 quantity: 1,
 value: "x3xxx"
 }
];
class RowRecord {
 constructor(rowsize = 4) {
 this.items = Array(rowsize).fill(null);
 this.rowSize = rowsize;
 }
 push(item) {
 const currentSize = this.size();
 // console.log(currentSize);
 if (currentSize < this.rowSize) {
 // replace 1 items with null based on index
 this.items.splice(currentSize, 1, item);
 }
 }
 get() {
 return this.items;
 }
 size() {
 return this.items.filter(item => item !== null).length;
 }
}
function getRecords() {
 const records = [];
 let rows = new RowRecord(); // fill default
 // create records
 for (let i = 0; i < input.length; i++) {
 // check for pending rows
 if (i !== 0 && rows.size() > 0) {
 records.push(rows);
 }
 // initiate new row
 rows = new RowRecord();
 const item = input[i];
 const quantity = parseInt(item.quantity, 10);
 const value = item.value;
 // +1 for printing the label for each product
 for (let j = 0; j <= quantity; j++) {
 if (j === 0) {
 // title label
 rows.push({
 id: item.id,
 header: true,
 quantity,
 value
 });
 } else {
 if (rows.size() === 4) {
 records.push(rows);
 rows = new RowRecord();
 }
 rows.push({
 id: item.id,
 header: false,
 quantity,
 value
 });
 }
 }
 }
 // push any pending rows
 records.push(rows);
 return records;
}
console.log(getRecords());

asked Dec 13, 2019 at 21:53
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

You can also use Array.prototype.reduce to generate the fixed size 2d array.

const input = [{
 id: 123, quantity: 4, value: "x1xxx"
}, {
 id: 234, quantity: 11, value: "x2xxx"
}, {
 id: 345, quantity: 1, value: "x3xxx"
}];
function getNewRecords(rowSize = 4) {
 return input.reduce((records, current) => {
 let items = [];
 Array.from({
 length: current.quantity + 1 // +1 for header column
 }).forEach((_, index) => {
 const record = {
 header: index === 0,
 id: current.id,
 quantity: current.quantity,
 value: current.value
 }
 if (items.length === rowSize) {
 records.push({ items, rowSize });
 items = [];
 }
 items.push(record);
 });
 if (items.length < rowSize) {
 items.push(...Array(rowSize - items.length).fill(null));
 }
 records.push({ items, rowSize });
 return records;
 }, []);
}
console.log(getNewRecords());

answered Jun 19, 2020 at 13:48
\$\endgroup\$
1
\$\begingroup\$

Separating your code out into functions could help readability. I tried writing the functions to each handle a single requirement of your data. Is rowSize really necessary, given that you have access to row.length?

function makeOutputHeader(input_obj) {
 return {...input_obj,header:true}
}
function* makeOutputValues(input_obj) {
 for (let i=0;i<input_obj.quantity;++i)
 yield {...input_obj,header:false}
}
function makeCells(input_obj) {
 return [
 makeOutputHeader(input_obj),
 ...makeOutputValues(input_obj)
 ];
}
function range(count) {
 return Array.from({length:count}).map((_,i)=>i);
}
function makeGrid(cells,width) {
 const height = Math.ceil(cells.length/width);
 const rows = range(height).map(
 row=>range(width).map(
 col=>cells[row*width+col] || null
 )
 )
 return rows
}
function rowsForInputObj(header,width) {
 const cells = makeCells(header);
 return makeGrid(cells,width);
}
function getRecords(input,width) {
 const rows_for_headers = input.map(
 inputObj=>rowsForInputObj(inputObj,width)
 );
 const all_rows = rows_for_headers.reduce((a,b)=>a.concat(b),[]);
 return all_rows;
}
console.log(getRecords(input,4));
answered Jul 19, 2020 at 14:58
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.