Let's say I have a 2D array filled with a lot of blank spaces, but there are smaller isolated 2D arrays contained between these blanks. For example:
var aVO = [
["col1", "col2", "col3", "col4", "col5", "col6", "col7", "col8", "col9"],
["", "", "", "", "", "", "", "", ""],
[1, 2, 3, "", "", "", "", "", ""],
[4, 5, 6, "", "", "a", "b", "", ""],
[7, 8, 9, "", "", "c", "d", "", 1],
["", "", "", "", "", "", "", "", 2],
["", "", "z", "y", "", "", "", "", 3],
["", "x", "w", "v", "", 7, 7, 7, ""],
["", "", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", "", ""],
["", "A1", "B1", "", "", "", "", "", ""],
["", "A2", "B2", "C2", "", "", "HELLO", "", ""]
]
I'm interested in converting this into eight 2D arrays:
[["col1", "col2", "col3", "col4", "col5", "col6", "col7", "col8", "col9"]]
[[1,2,3],[4,5,6],[7,8,9]]
[["a","b"],["c","d"]]
[[1],[2],[3]]
[["", "z","y"],["x","w", "v"]]
[[7,7,7]]
[["A1","B1",""],["A2","B2","C2"]]
[["HELLO"]]
What's the best approach to extract these smaller 2D arrays? I was thinking about iterating row-by-row but it's hard to visualize how to elegantly extract data like [["", "z","y"],["x","w","v"]] (note how "x" isn't directly below "z", and therefore the resulting 2D array needs to reflect that shift). Thanks for any help!
Here's an approach using Set and Map instances to keep track of groups of cells:
Create cells out of the 2d array
Create an empty Map in which we will store for each cell with a value to which group it belongs
Loop over each cell
If a cell is empty, go to the next one
If a cell has a value
Create a group for it. The group marks a top left and bottom right position and keeps track of a set of cells that belong to it.
Check which adjacent cells already belong to a group
Merge the newly created group with all of the groups found for adjacent cells
Collect all unique groups from the Map
For each unique group, slice out the part between its top left and bottom right corner from the initial grid
const Cell = memo(
(r, c) => ({ r, c }),
([r, c]) => `${r}_${c}`
);
Cell.neighbors = ({ r, c }) => [
Cell(r, c + 1), // Right
Cell(r + 1, c), // Down
Cell(r, c - 1), // Left
Cell(r - 1, c), // Up
];
// Create a single-cell group
const Group = (cell) => ({
minR: cell.r,
maxR: cell.r + 1,
minC: cell.c,
maxC: cell.c + 1,
cells: new Set([cell])
});
// Merge two groups into a new one
Group.merge = (g1, g2) => ({
minR: Math.min(g1.minR, g2.minR),
maxR: Math.max(g1.maxR, g2.maxR),
minC: Math.min(g1.minC, g2.minC),
maxC: Math.max(g1.maxC, g2.maxC),
cells: new Set([ ...g1.cells, ...g2.cells ])
});
// Take a grid and slice out the part covered by a group
Group.extractFromGrid = grid => ({ minR, maxR, minC, maxC }) => grid
.slice(minR, maxR)
.map(row => row.slice(minC, maxC));
// Create all cells with their values
const grid = getData();
const allCells = grid.flatMap(
(row, ri) => row.map(
(value, ci) => Cell(ri, ci)
)
);
const groupPerCell = new Map();
allCells.forEach(current => {
const inIsland = grid[current.r][current.c] !== "";
if (inIsland) {
const newGroup = Cell
.neighbors(current)
.filter(c => groupPerCell.has(c))
.map(c => groupPerCell.get(c))
.reduce(Group.merge, Group(current));
// Store a reference to the group for each member
newGroup.cells.forEach(c => {
groupPerCell.set(c, newGroup);
});
}
});
const allGroups = [...new Set(groupPerCell.values())];
const allValues = allGroups.map(Group.extractFromGrid(grid));
console.log(allValues);
function memo(f, hash) {
const cache = {};
return (...args) => {
const k = hash(args);
if (!cache[k]) cache[k] = f(...args);
return cache[k];
}
}
function getData() { return [
["col1", "col2", "col3", "col4", "col5", "col6", "col7", "col8", "col9"],
["", "", "", "", "", "", "", "", ""],
[1, 2, 3, "", "", "", "", "", ""],
[4, 5, 6, "", "", "a", "b", "", ""],
[7, 8, 9, "", "", "c", "d", "", 1],
["", "", "", "", "", "", "", "", 2],
["", "", "z", "y", "", "", "", "", 3],
["", "x", "w", "v", "", 7, 7, 7, ""],
["", "", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", "", ""],
["", "A1", "B1", "", "", "", "", "", ""],
["", "A2", "B2", "C2", "", "", "HELLO", "", ""]
]; }
I'm trying to take this array of arrays,
const parsedCsvData = [
[
"Passage",
"Percentage of",
"constraint2",
"1",
"2",
"",
"",
"",
"",
"",
"",
""
],
[
"",
"",
"",
"",
"",
"",
"",
"",
"Avg A Param",
"",
"0.3",
"0.9"
],
[
"Item",
"Include",
"constraint1",
"1",
"4",
"",
"",
"",
"",
"",
"",
""
],
[
"",
"",
"",
"",
"",
"",
"",
"",
"Item Identifier",
"I105_15201",
"",
""
]
]
and populate this object with their values
const template = {
"attributeName": "",
"constraintType": "",
"objectType": "",
"filters": [
{
"objectType": "",
"attributeName": "",
"values": "",
"valueLowerBound": "",
"valueUpperBound": ""
}
],
"upperBound": "",
"description": "",
"lowerBound": ""
}
each array from parsedCsvData was a row in a CSV file I parsed. Each value in the array of arrays is indexed based off another array
const csvHeaders = [
"objectType",
"constraintType",
"description",
"lowerBound",
"upperBound",
"attributeName",
"referenceValue",
"scope",
"filters",
"values",
"valueLowerBound",
"valueUpperBound"
]
For example, in the first sub array of parsedCsvData Passage is at index 0 and the value for objectType in csvHeaders. Similarly, description is at index 2 and is constraint1 and constraint2 respectively.
Additionally, if there exists a filters value at index 8 in the csv a new row was created. After parsing, this created a new sub array for each filter value. However, each filters value and the following three, values, valueLowerBound and valueUpperBound belong in the same template object as a subarray under the filters key.
Here is an example of the output I am trying to accomplish given what I posted above. Never mind the empty key/value pairs.
[{
"constraintType": "Percentage of",
"objectType": "Passage",
"filters": [
{
"attributeName": "Avg A Param",
"values": "",
"valueLowerBound": "0.3",
"valueUpperBound": "0.9"
} // there may be multiple filter objects as part of this array
],
"upperBound": "2",
"description": "constraint2",
"lowerBound": "1"
},
{
"constraintType": "Include",
"objectType": "Item",
"filters": [
{
"attributeName": "Item Identifier",
"values": "I105_15201",
"valueLowerBound": "",
"valueUpperBound": ""
}
],
"upperBound": "4",
"description": "constraint1",
"lowerBound": "1"
}
]
I've tried mapping the csvHeaders array, attempting to use their indices and then do a map of the the parsedCsvData values and assign them to the template object, but can't seem to get it to work. Any help would be much appreciated.
An approach by checking the first element of the nested arra for either assign a new object or assign a new nested object.
const
parsedCsvData = [["Passage", "Percentage of", "constraint2", "1", "2", "", "", "", "", "", "", ""], ["", "", "", "", "", "", "", "", "Avg A Param", "", "0.3", "0.9"], ["Item", "Include", "constraint1", "1", "4", "", "", "", "", "", "", ""], ["", "", "", "", "", "", "", "", "Item Identifier", "I105_15201", "", ""]],
template = ["objectType", "constraintType", "description", "lowerBound", "upperBound", "xxxx", "referenceValue", "scope", "attributeName", "values", "valueLowerBound", "valueUpperBound"],
result = parsedCsvData.reduce((r, a) => {
const
assign = (object, target, value) => {
const
keys = target.split('.'),
last = keys.pop();
keys.reduce((o, k) => o[k] = o[k] || {}, object)[last] = value;
};
if (a[0]) {
r.push(a.reduce((t, v, i) => {
if (v) assign(t, template[i], v);
return t;
}, {}));
} else {
r[r.length - 1].filters = r[r.length - 1].filters || [];
r[r.length - 1].filters.push(a.reduce((t, v, i) => {
if (v) assign(t, template[i], v);
return t;
}, {}));
}
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I'm facing an issue in my code that I can't find how to fix.
I'm getting the following error:
Cannot read property 'createDocumentFragment' of undefined - jquery-3.3.1.min.js:2
Here is my code :
$.ajax({
url: '/ajax/getPvaSession.php'
}).done(function (data) {
let content = data['content'];
console.log(content);
$('body').append('<table id="table"></table>');
for (let i=0;i<content[i].length;++i) {
$('table').append('<tr id="' + i + '"></tr>');
for (let j=0; j<content.length; ++j){
$(i).append('<td id="' + i + '_' + j + '">' + content[i][j] + '</td>')
}
}
})
My console.log shows this (It is a simple matrix):
(8) [Array(31), Array(31), Array(31), Array(31), Array(31), Array(31), Array(31), Array(31)]
0: (31) ["Projet", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30"]
1: (31) ["Administrateur Réseau", "1", "1", "1", "1", "1", "", "", "1", "1", "0.5", "", "", "", "", "1", "1", "1", "1", "1", "", "", "", "1", "1", "1", "1", "", "", "1", "1"]
2: (31) ["Intercontrat", "", "", "", "", "", "", "", "", "", "0.5", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
3: (31) ["Formation", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
4: (31) ["Congés payés", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
5: (31) ["Congés sans solde", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
6: (31) ["Incentive", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
7: (31) ["Maladie", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
length: 8
I read online that many people faced this error using this the wrong way, but I'm not using it anywhere.
Could you clarify it? And explain the error if possible so I won't do the mistake next time.
Thanks!
You need to loop thru the outer array as content.length and not content[0].length. and use content[0].length in the inner array.
Like:
var content = [["Administrateur Réseau","1","1","1","1","1","","","1","1","0.5","","","","","1","1","1","1","1","","","","1","1","1","1","","","1","1"],["Intercontrat","","","","","","","","","","0.5","","","","","","","","","","","","","","","","","","","",""],["Formation","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],["Congés payés","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],["Congés sans solde","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],["Incentive","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],["Maladie","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""]]
$('body').append('<table id="table"></table>');
for (let i = 0; i < content.length; ++i) { //Remove the [i]. This will loop thru all contents
var tr = $('<tr id="' + i + '"></tr>'); //Create a tr element and store on a variable
$('table').append(tr);
for (let j = 0; j < content[i].length; ++j) { //Add the [i]. This will loop thru the inner array
tr.append('<td id="' + i + '_' + j + '">' + content[i][j] + '</td>'); //Append the td string on tr variable
}
}
td {
border: 1px solid #dddddd;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Another option is to construct an HTML string. And use that to append in the body
var content = [["Administrateur Réseau","1","1","1","1","1","","","1","1","0.5","","","","","1","1","1","1","1","","","","1","1","1","1","","","1","1"],["Intercontrat","","","","","","","","","","0.5","","","","","","","","","","","","","","","","","","","",""],["Formation","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],["Congés payés","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],["Congés sans solde","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],["Incentive","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],["Maladie","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""]]
var html = "";
html += "<table>";
for (let i = 0; i < content.length; ++i) {
html += "<tr id='" + i + "'>";
for (let j = 0; j < content[i].length; ++j) {
html += '<td id="' + i + '_' + j + '">' + content[i][j] + '</td>';
}
html += "</tr>";
}
html += "</table>";
$('body').append(html);
td {
border: 1px solid #dddddd;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I am using map method to convert from an object to an array. What is the issue in the following code?
var data = {
"productName": "fsdfsdf",
"productDesc": "",
"category": null,
"categoryName": "",
"style": null,
"styleName": "",
"substyle": null,
"substyleName": "",
"store": null,
"storeName": "",
"stand": null,
"standName": "",
"rack": null,
"rackName": "",
"roll": null,
"rollName": "",
"color": null,
"width": "",
"widthunit": "meter",
"length": 0,
"lengthunit": "meter",
"pieces": "",
"cutofquantity": "",
"estimatedConsumption": ""
}
var key = $.map(data, function(value, index) {
return index;
});
var value = $.map(data, function(value, index) {
return value;
});
console.log(value)
Please refer to this JSFiddle for a live example.
Because you have length: 0 as one of your properties, jQuery thinks that the object is an array instead of an object.
It then loops over the numerical indexes from 0 to 0 (not inclusive) and generates a zero length array.
Here is the alternate if you want to use with length:0
var data = {
"productName": "fsdfsdf",
"productDesc": "",
"category": null,
"categoryName": "",
"style": null,
"styleName": "",
"substyle": null,
"substyleName": "",
"store": null,
"storeName": "",
"stand": null,
"standName": "",
"rack": null,
"rackName": "",
"roll": null,
"rollName": "",
"color": null,
"width": "",
"widthunit": "meter",
"length": 0,
"lengthunit": "meter",
"pieces": "",
"cutofquantity": "",
"estimatedConsumption": ""
};
for(var key in data) {
if(data.hasOwnProperty(key)) {
console.log(key) ;
console.log(data[key]);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You could do something like this below:
var data = {
"productName": "fsdfsdf",
"productDesc": "",
"category": null,
"categoryName": "",
"style": null,
"styleName": "",
"substyle": null,
"substyleName": "",
"store": null,
"storeName": "",
"stand": null,
"standName": "",
"rack": null,
"rackName": "",
"roll": null,
"rollName": "",
"color": null,
"width": "",
"widthunit": "meter",
"length": 0,
"lengthunit": "meter",
"pieces": "",
"cutofquantity": "",
"estimatedConsumption": ""
};
var arr = Object.keys(data).map(function(k) { return data[k] });
console.log(arr)
Fiddle to play around: https://jsfiddle.net/u5t4L55g/
Loop through each property of the object and push the key and value in array like below. Hope this will help you.
var data = {
"productName": "fsdfsdf",
"productDesc": "",
"category": null,
"categoryName": "",
"style": null,
"styleName": "",
"substyle": null,
"substyleName": "",
"store": null,
"storeName": "",
"stand": null,
"standName": "",
"rack": null,
"rackName": "",
"roll": null,
"rollName": "",
"color": null,
"width": "",
"widthunit": "meter",
"length": 0,
"lengthunit": "meter",
"pieces": "",
"cutofquantity": "",
"estimatedConsumption": ""
}
var value = [];
var key = [];
for (var property in data) {
key.push(property);
value.push(data[property]);
}
console.log(value)
var key = Object.keys(data).map(function(index, value) { return index });
var value = Object.keys(data).map(function(index, value) { return data[index] });
So it is giving key and value pairs