dynamically get columns from 2D array - javascript

I have a 2D array of row,through which i want get the column coordinates/information just like i got for the row(rowArr2D)
So,in my Column(colArr2D) i'm just getting all 4th position values in the array since i passed have oRowCount in the function
my goal is to get all columns respectively.
Example:
Row:[ [ 0, 1, 2, 3, 4, 5, 6 ], [ 0, 1, 2, 3, 4, 5, 6 ], [ 0, 1, 2, 3, 4, 5, 6 ], [ 0, 1, 2, 3, 4, 5, 6 ] ]
Columns: [[0,1,2,3],[0,1,2,3],[0,1,2,3],[0,1,2,3],[0,1,2,3],[0,1,2,3],[0,1,2,3]]
mockTable = { // mocking the portions of my code
GetRowsCount : () => 4,
GetRow: (x) => ({
GetCellsCount : () => 7,
GetCell : (x) => x
})
}
CTable_prototype_GetTableMapping = function(currentTable)
{
//get row information
let oRowCount = currentTable.GetRowsCount();
const rowArr2D = Array(oRowCount);
for (let i = 0; i < oRowCount; i++) {
//get cell information and cell count
let oRow = currentTable.GetRow(i);
let oCellCount = oRow.GetCellsCount();
rowArr2D[i] = Array(oCellCount);
for (let j = 0; j < oCellCount; j++) {
//get cell content
let oCell = oRow.GetCell(j);
rowArr2D[i][j] = oCell;
}
}
// get column information
const colArr2D = (array, colCount) => {
const result = [];
array.forEach(e => {
result.push(e[colCount]);
});
console.log(result);
return result;
};
colArr2D(rowArr2D, oRowCount);
return rowArr2D
console.log(rowArr2D);
};
const theArray = CTable_prototype_GetTableMapping(mockTable);
console.log("full 2D array", theArray)

Give this a try
const colArr2D = (array) =>
array[0].map((a, i) =>
array.map(b => b[i])
);
const arr = [[1,2,3],[4,5,6],[7,8,9]];
console.log(colArr2D(arr))

Related

turn a flat array into cell like objects for a grid

I have an array that looks like similar to this,
[
['column1', 'column2', 'column3', 'column4', 'column5'],
['2column1', '2column2', '2column3', '2column4', '2column5']
]
I wanting to turn this array into table that looks similar to this,
header1
header2
header3
header4
header5
column1
column2
column3
column4
column5
2column1
2column2
2column3
2column4
2column5
I want to turn array above into an array of objects if possible that would look like this,
[
[
{ col:a, row: 1, cell_value: 'column1'},
{ col:b, row: 1, cell_value: 'column2'},
{ col:c, row: 1, cell_value: 'column3'},
{ col:d, row: 1, cell_value: 'column4'},
{ col:e, row: 1, cell_value: 'column5'}
],
[
{ col:a, row: 2, cell_value: '2column1'},
{ col:b, row: 2, cell_value: '2column2'},
{ col:c, row: 2, cell_value: '2column3'},
{ col:d, row: 2, cell_value: '2column4'},
{ col:e, row: 2, cell_value: '2column5'}
]
]
I have a function to create the column letters,
export const columnToLetter = (column) => {
let temp, letter = '';
while (column > 0) {
temp = (column - 1) % 26;
letter = String.fromCharCode(temp + 65) + letter;
column = (column - temp - 1) / 26;
}
return letter;
}
and this is my attempt to create the above array objects,
const data = payload.formatted_values.map((value, index) => {
let columnCount = 0;
while (columnCount <= payload.formatted_values.length) {
const singleCell = {
col: columnToLetter(index+1),
row: columnCount+1,
cell_value: value[columnCount]
}
columnCount++;
return singleCell;
}
});
But the output I get is incorrect, I get this structure,
{col: 'A', row: 1, cell_value: 'Fav'}
{col: 'B', row: 1, cell_value: 'red'}
{col: 'C', row: 1, cell_value: ''}
Which is not what I want, can any advise how I would turn the flat array I start with into a object with the attributes I want?
You could map a nested result.
const
data = [['column1', 'column2', 'column3', 'column4', 'column5'], ['2column1', '2column2', '2column3', '2column4', '2column5']],
result = data.map((a, row) => a.map((cell_value, col) => ({
col: (col + 10).toString(36).toUpperCase(),
row: row + 1,
cell_value
})));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could just loop over it like so:
function makeColumn(arr)
{
var outArr = []
var rowCounter = 0
var cCounter = 97
arr.forEach((item,index) => {
outArr.push([])
item.forEach((i2,ind2) => {
outArr[index].push({
col:String.fromCharCode(cCounter++),
row: rowCounter,
cell_value: arr[rowCounter][ind2]
})
})
rowCounter++
cCounter = 97
})
return outArr
}
Using for and map()
const data = [
['column1', 'column2', 'column3', 'column4', 'column5'],
['2column1', '2column2', '2column3', '2column4', '2column5']
]
const res = []
for (let i = 0; i < data.length; i++) {
res.push(data[i].map((item, index) => {
return { col: String.fromCharCode(index+97), row: i+1, cell_value: item }
}))
}
console.log(res)
You can simply achieve this by just using Array.map() method.
Live Demo :
const arr = [
['column1', 'column2', 'column3', 'column4', 'column5'],
['2column1', '2column2', '2column3', '2column4', '2column5']
];
const res = arr.map((elem, index) => {
return elem.map((col, i) => {
return {
col: String.fromCharCode(97 + i),
row: index + 1,
cell_value: col
}
})
});
console.log(res);

How to write a proper constructor function extending the Array class

Scenario
I have the following piece of code:
const composeMatrix = (nRow, nCol, filler) => Array(nRow).fill(Array(nCol).fill(filler));
class Matrix extends Array {
constructor({ nRows = 3, nCols = 3, filler = 0 } = {}) {
super(...composeMatrix(nRows, nCols, filler));
}
makeTranspose() {
const mat = this;
const column = mat[0];
return column.map((_, i) => {
return mat.map((row) => row[i]);
});
}
}
I'm instantiating a new Matrix like this:
const mat = new Matrix({ nRows: 4, filler: 1 });
Logging mat to the console gives me as expected,
Matrix(4) [
[ 1, 1, 1 ],
[ 1, 1, 1 ],
[ 1, 1, 1 ],
[ 1, 1, 1 ]
]
Problem
Now when I call the makeTranspose method of the class, it returns me this:
[
Matrix(4) [ 1, 1, 1, 1 ],
Matrix(4) [ 1, 1, 1, 1 ],
Matrix(4) [ 1, 1, 1, 1 ]
]
Expected output:
Matrix(3) [
[ 1, 1, 1, 1 ],
[ 1, 1, 1, 1 ],
[ 1, 1, 1, 1 ]
]
What I figured is, the map function calls the constructor of this subclass every time while iterating through the array, which in turn calls super, which then calls the composeMatrix function and a new Matrix gets made.
How can I fix this?
I want a class to extend Array with some added methods.
The constructor needs to take some relevant parameters and function as expected.
I don't want to add functions to the prototype.
A matrix is not an array. You're better off using composition over inheritance.
Array.create = (length, mapping) =>
Array.from({ length }, (value, index) => mapping(index));
class Matrix {
constructor(rows, cols, data) {
this.rows = rows;
this.cols = cols;
this.data = data;
}
static create(rows, cols, mapping) {
const data = Array.create(rows, row =>
Array.create(cols, col => mapping(row, col)));
return new Matrix(rows, cols, data);
}
transpose() {
const { rows, cols, data } = this;
return Matrix.create(cols, rows, (row, col) => data[col][row]);
}
}
const mat = Matrix.create(4, 3, (row, col) => 1);
console.log(mat.transpose());
Using a functional style of programming.
const array = (length, mapping) =>
Array.from({ length }, (value, index) => mapping(index));
const Matrix = (rows, cols, data) => ({ rows, cols, data });
const matrix = (rows, cols, mapping) =>
Matrix(rows, cols, array(rows, row =>
array(cols, col => mapping(row, col))));
const transpose = ({ rows, cols, data }) =>
matrix(cols, rows, (row, col) => data[col][row]);
const mat = matrix(4, 3, (row, col) => 1);
console.log(transpose(mat));

Get specific data from array and put in other array

I have this result in javascript and i want to get data that has value more that 3 and i want to put in other array .
"availableDates": {
"2020-01-24": 1,
"2020-01-23": 3,
"2020-01-22": 2,
"2020-01-21": 1,
"2020-01-25": 4,
"2021-01-07": 1
}
I group here :
const formattedDate = x.reduce((acc,el) => {
const date = el.split(" ")[0];
acc[date] = (acc[date] || 0) + 1;
return acc;
}, {});
now I want to put in other array all that date that has value more than 3 . For example
newarray = [ "2020-01-23", "2020-01-25" ]
Why don't use a simple .filter() over keys of "availableDates":
const grouped = {
"availableDates": {
"2020-01-24": 1,
"2020-01-23": 3,
"2020-01-22": 2,
"2020-01-21": 1,
"2020-01-25": 4,
"2021-01-07": 1
}
};
const newArray = Object.keys(grouped.availableDates).filter((key) => grouped.availableDates[key] >= 3);
console.log(newArray);
You can simply use a for...in loop to iterate over object keys and filter them:
const data = {
"2020-01-24": 1,
"2020-01-23": 3,
"2020-01-22": 2,
"2020-01-21": 1,
"2020-01-25": 4,
"2021-01-07": 1
};
const reducer = (obj, val) => {
const result = [];
for(key in obj) {
if(obj[key] >= val)
result.push(key);
};
return result;
};
console.log(reducer(data, 3));
You could have something like this. I write a complete bunch of the code to make you able to copy/past to test
var availableDates = new Array()
var availableDates = {
"2020-01-24": 1,
"2020-01-23": 3,
"2020-01-22": 2,
"2020-01-21": 1,
"2020-01-25": 4,
"2021-01-07": 1
}
var results = new Array();
for (date in availableDates){
if (availableDates[date] >= 3){
results.push(date)
}
}
console.log(results)

Converting relationships between data inside a JavaScript Array

I have got a function that produces an array that is made up of X amount of sub-arrays containing Y amount of objects. Both of these factors are passed to a function to produce an array that looks something like this:
[
[ { '0': 3 }, { '1': 4 }, { '2': 6 }, 'Estimate:': '0jvyt8a' ],
[ { '0': 4 }, { '1': 6 }, { '2': 3 }, 'Estimate:': 'mc973fs' ],
[ { '0': 4 }, { '1': 1 }, { '2': 3 }, 'Estimate:': 'vwsfh8k' ],
[ { '0': 4 }, { '1': 3 }, { '2': 5 }, 'Estimate:': 'n6xzge3' ],
[ { '0': 8 }, { '1': 7 }, { '2': 1 }, 'Estimate:': 'v0jn7bh' ]
]
My question is, is there a way I can convert this array from this structure. To a structure shown below:
[
[1,{1: "vwsfh8k"}, {2: "v0jn7bh"}]
[3,{1: "0jvyt8a"}, {2: "mc973fs"}, {3:"vwsfh8k"}, {4:"n6xzge3"}]
]
Basically, my aim is to take the original array generated by the script (see below) and pass it through another function to record how many times each number was present and what it's 'estimate' number was.
In this example, I just created random numbers between 0 and 10 so an option would be to iterate and count each value I guess but unfortunately, I can't do this because eventually I will be using 5-letter combinations instead of numbers but numbers were easiest to show for an example and proof of concept.
So, I guess, I need to get an array of each unique value and then look at each value up in the original array to find out what estimate IDs have it present. Unfortunately, I don't have even an idea of where, to begin with, this, so I was hoping you guys can help.
Code to generate random array:
// Making an empty array
const arr = [];
//Generating the estimate IDs and placing them all in their own object in their own array.
function estimateGen(length, nodes) {
for (var i = 0; i < length; i++) {
const estimate = [];
let estimateVal = Math.random().toString(36).replace('0.','').slice(0,7);
estimate[`Estimate:`] = estimateVal;
arr.push(estimate);
nodeGen(estimate, nodes)
}
}
// Adding x amount of nodes between 1 and 10 into each estimate sub-array in their own objects.
function nodeGen(estimate, nodes) {
for (var i = 0; i < nodes; i++) {
const node = {};
let nodeID = Math.floor(Math.random() * 10) + 1;
node[i] = nodeID;
estimate.push(node);
}
}
// Calling the function and saying how many nodes per estimate we want.
estimateGen(5, 3);
console.log(arr);
If you have any suggestions on how to improve this code or as to why the estimate values in the sub-array are always last in the array that would be very helpful.
Thank you
--- EDIT ---
I have changed the code that generates the original array to produce a simpler array.
// Making an empty array
const arr = [];
//Generating the estimate IDs and placing them all in their own object in their own array.
function estimateGen(length, nodes) {
for (var i = 0; i < length; i++) {
const estimate = [];
let estimateVal = Math.random().toString(36).replace('0.','').slice(0,7);
estimate.push(estimateVal);
arr.push(estimate);
nodeGen(estimate, nodes)
}
}
// Adding x amount of nodes between 1 and 10 into each estimate sub array in their own objects.
function nodeGen(estimate, nodes) {
for (var i = 0; i < nodes; i++) {
let nodeID = Math.floor(Math.random() * 10) + 1;
estimate.push(nodeID);
}
}
// Calling the function and saying how many nodes per estimate we want.
estimateGen(5, 3);
console.log(arr);
From this code I now get the result:
[
[ 'p68xw8h', 5, 4, 6 ],
[ 'wn2yoee', 5, 4, 5 ],
[ '1w01tem', 9, 7, 4 ],
[ 'we3s53f', 8, 8, 8 ],
[ '5nrtp09', 3, 3, 8 ]
]
Would there be a way to count the number of times the values on the right appear and what 'estimate' ID at [0] it appears in?
Thank you.
First, let's redesign your input data and results to be a more useful format:
// input
[
{ nodes: [3, 4, 6], Estimate: '0jvyt8a' },
{ nodes: [4, 6, 3], Estimate: 'mc973fs' },
{ nodes: [4, 1, 3], Estimate: 'vwsfh8k' },
{ nodes: [4, 3, 5], Estimate: 'n6xzge3' },
{ nodes: [8, 7, 1], Estimate: 'v0jn7bh' }
];
// result
{
1: ["vwsfh8k", "v0jn7bh"],
3: ["0jvyt8a", "mc973fs", "vwsfh8k", "n6xzge3"],
...
]
Then the code would be:
const input = [
{ nodes: [3, 4, 6], Estimate: '0jvyt8a' },
{ nodes: [4, 6, 3], Estimate: 'mc973fs' },
{ nodes: [4, 1, 3], Estimate: 'vwsfh8k' },
{ nodes: [4, 3, 5], Estimate: 'n6xzge3' },
{ nodes: [8, 7, 1], Estimate: 'v0jn7bh' }
];
const result = {};
input.forEach(({
nodes,
Estimate: e
}) =>
nodes.forEach(n => {
if (!result[n]) {
result[n] = [];
}
result[n].push(e);
})
);
console.log(result);
You can create the data with:
// Making an empty array
const arr = [];
//Generating the estimate IDs and placing them all in their own object in their own array.
function estimateGen(length, nodes) {
for (var i = 0; i < length; i++) {
let estimateVal = Math.random().toString(36).replace('0.', '').slice(0, 7);
const estimate = {
Estimate: estimateVal,
nodes: []
}
arr.push(estimate);
nodeGen(estimate, nodes)
}
}
// Adding x amount of nodes between 1 and 10 into each estimate sub array in their own objects.
function nodeGen(estimate, nodes) {
for (var i = 0; i < nodes; i++) {
let nodeID = Math.floor(Math.random() * 10) + 1;
estimate.nodes.push(nodeID);
}
}
// Calling the function and saying how many nodes per estimate we want.
estimateGen(5, 3);
console.log(arr);
I've reformatted your array. The output is different, but you can still use it.
var arr = [
{ '0': 3 , '1': 4 , '2': 6 , 'Estimate:': '0jvyt8a' },
{ '0': 4 , '1': 6 , '2': 3 , 'Estimate:': 'mc973fs' },
{ '0': 4 , '1': 1 , '2': 3 , 'Estimate:': 'vwsfh8k' },
{ '0': 4 , '1': 3 , '2': 5 , 'Estimate:': 'n6xzge3' },
{ '0': 8 , '1': 7 , '2': 1 , 'Estimate:': 'v0jn7bh' }
];
var num = [1, 3, 4, 5, 6, 7, 8];
num = num.map(n =>
[n, ...(
arr.filter(a => [0, 1, 2].some(nm => a[nm] === n))
.map(v => v["Estimate:"])
)]);
console.log(num);
For getting a counting object you could take the values as key and estimates as key for the count of same values.
function estimateGen(length, nodes) {
var array = [];
for (var i = 0; i < length; i++) {
array.push([Math.random().toString(36).replace('0.','').slice(0,7), ...nodeGen(nodes)]);
}
return array;
}
function nodeGen(nodes) {
var result = [];
for (var i = 0; i < nodes; i++) {
result.push(Math.floor(Math.random() * 10) + 1);
}
return result;
}
function count(data) {
return data.reduce((r, [estimate, ...values]) => {
values.forEach(v => {
r[v] = r[v] || {};
r[v][estimate] = (r[v][estimate] || 0) + 1;
});
return r;
}, {});
}
var temp = estimateGen(5, 3);
console.log(temp);
console.log(count(temp));
.as-console-wrapper { max-height: 100% !important; top: 0; }

BASIC Javascript array function, issue is known but I cannot fathom a solution

In the below function I am attempting to get an output which resembles this:
[[1,1,1,1],[2,2,2], 4,5,10,[20,20], 391, 392,591].
I can see that the problem I have embedded is that I am always adding the temp array with a push to the functions return, as a result, all of the individual numbers apart from the last number in the for each function are being pushed into the target array with the array object also.
I feel as though I need a further conditonal check but for the life of me I am unable to come up with solution which works.
Any suggestions would be much appreciated.
const sortme = (unsortedArr)=> {
let tempArr = [];
let outputArr = [];
const reorderedArr = unsortedArr.sort((a,b) => a-b);
reorderedArr.forEach((number, i) => {
if ((i === 0) || (reorderedArr[i] === reorderedArr[i-1])) {
tempArr.push(number);
}
else {
outputArr.push(tempArr);
tempArr = [];
tempArr.push(number);
}
})
outputArr.push(tempArr[0]);
return outputArr;
}
const unsortedArr = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
sortme(unsortedArr);
i would make a deduped copy and .map() it to transform the values into arrays containing values from the original ( sorted ) array that you get using a .forEach :
const unsortedArr = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20];
const sortMe = (arr) => {
arr = arr.sort((a, b) => a - b);
// a short way to dedupe an array
// results in : 1, 2, 4, 5, 10, 20, 391, 392, 591
let dedupe = [...new Set(arr)];
let tmpArr;
return dedupe.map(e => {
tmpArr = []; // empty tmpArr on each iteration
// for each element of the deduped array, look for matching elements in the original one and push them in the tmpArr
arr.forEach(a => {
if (a === e)
tmpArr.push(e);
})
if(tmpArr.length === 1)
return tmpArr[0]; // in case you have [4] , just return the 4
else
return tmpArr; // in case you have [1,1,1,1]
// shorthand for the if/else above
// return tmpArr.length === 1 ? tmpArr[0] : tmpArr;
});
}
const result = sortMe(unsortedArr);
console.log(result);
This should work (using reduce):
const unsortedArr = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
let lastValue = null;
var newArr = unsortedArr.sort((a,b) => a-b).reduce((acc, value) => {
if (acc.length == 0 || ((acc.length > 0 || !acc[acc.length-1].length) && lastValue !== value)) {
acc.push(value);
} else if (acc.length > 0 && lastValue === value) {
acc[acc.length-1] = (acc[acc.length-1].length ? acc[acc.length-1].concat([value]): [value, value]);
}
lastValue = value;
return acc;
}, []);
console.log(newArr);
And another approach, just for fun:
const unsortedArr = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
var arr = unsortedArr.sort((a,b) => a-b).reduce((acc, value) => {
if (acc.length > 0 && acc[acc.length-1].includes(value)) {
acc[acc.length-1].push(value);
} else {
acc.push([value])
}
return acc;
}, []).map((v) => v.length > 1 ? v: v[0]);
console.log(arr);
I hope the below one is quite simple;
function findSame(pos, sortedArr){
for(let i =pos; i<sortedArr.length; i++){
if(sortedArr[i] !== sortedArr[pos]){
return i
}
}
}
function clubSameNumbers(unsortedArr){
let sortedArr = unsortedArr.sort((a,b)=>a-b)
//[ 1, 1, 1, 1, 2, 2, 2, 4, 5, 10, 20, 20, 391, 392, 591 ]
let result = []
for(let i = 0; i < sortedArr.length; i = end){
let start = i
var end = findSame(i, sortedArr)
let arr = sortedArr.slice(i, end)
arr.length > 1 ? result.push(arr) : result.push(...arr)
}
return result
}
console.log(clubSameNumbers([1,2,4,591,392,391,2,5,10,2,1,1,1,20,20]))
//[ [ 1, 1, 1, 1 ], [ 2, 2, 2 ], 4, 5, 10, [ 20, 20 ], 391, 392, 591 ]

Categories

Resources