Related
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);
I have an array of objects :
const routes = [
{ id: 1, path: "/", element: <HomePage /> },
{ id: 2, path: "/about", element: <AboutPage /> },
{ id: 3, path: "/review", element: <ReviewPage /> },
];
I have to loop though the array by the id and get every +2 item.
So by explanation the first item would be : id : 1
then we do +2 and next item is id:3
third item : id : 2
fourth item : id : 1
fifth item : id : 3
etc...
How would that be implemented?
You can use closure in this case
const routes = [{id:1,path:"/",element:"<HomePage />"},{id:2,path:"/about",element:"<AboutPage />" },{ id:3,path:"/review",element:"<ReviewPage />" }];
const makeNext = (size, step = 2) => {
let i = size - step;
return () => {
i += step;
if (i >= size) i -= size;
return i;
}
};
const nextId = makeNext(routes.length);
console.log(routes[nextId()]);
console.log(routes[nextId()]);
console.log(routes[nextId()]);
console.log(routes[nextId()]);
console.log(routes[nextId()]);
.as-console-wrapper { max-height: 100% !important; top: 0 }
I think that you will be in need to use a while until the condition you want and take an value like i = 1 (for example). Next you should take your element id = i and add to i + 2. And to finish you just need to verify if (i > 3) in this case you set i = i - 3. The code should work, here is an example :
const routes = [
{ id: 1, path: "/", element: <HomePage /> },
{ id: 2, path: "/about", element: <AboutPage /> },
{ id: 3, path: "/review", element: <ReviewPage /> },
];
i = 1
while (True) {
console.log(routes[i]);
i += 2;
if (i > 3) { i -= 3}
}
I believe that this could be of help to you.
https://jsfiddle.net/codyrowirthpaige/gr3cy4ek/
const arr = [
1,2,3,4
];
// return every second item in the array
function everySecond(arr) {
var newArr = [];
for (var i = 0; i < arr.length; i += 2) {
newArr.push(arr[i]);
}
console.log(newArr)
return newArr;
}
everySecond(arr);
I've taken the following sample from a different question. And I am able to identify the object. But I also need to find our the position of that object. For example:
var arr = [{
Id: 1,
Categories: [{
Id: 1
},
{
Id: 2
},
]
},
{
Id: 2,
Categories: [{
Id: 100
},
{
Id: 200
},
]
}
]
If I want to find the object by the Id of the Categories, I can use the following:
var matches = [];
var needle = 100; // what to look for
arr.forEach(function(e) {
matches = matches.concat(e.Categories.filter(function(c) {
return (c.Id === needle);
}));
});
However, I also need to know the position of the object in the array. For example, if we are looking for object with Id = 100, then the above code will find the object, but how do I find that it's the second object in the main array, and the first object in the Categories array?
Thanks!
Well, if every object is unique (only in one of the categories), you can simply iterate over everything.
var arr = [{
Id: 1,
Categories: [{Id: 1},{Id: 2}]
},
{
Id: 2,
Categories: [{Id: 100},{Id: 200}]
}
];
var needle = 100;
var i = 0;
var j = 0;
arr.forEach(function(c) {
c.Categories.forEach(function(e) {
if(e.Id === needle) {
console.log("Entry is in position " + i + " of the categories and in position " + j + " in its category.");
}
j++;
});
j = 0;
i++;
});
function findInArray(needle /*object*/, haystack /*array of object*/){
let out = [];
for(let i = 0; i < haystack.lenght; i++) {
if(haystack[i].property == needle.property) {
out = {pos: i, obj: haystack[i]};
}
}
return out;
}
if you need the position and have to filter over an property of the object you can use a simple for loop. in this sample your result is an array of new object because there can be more mathches than 1 on the value of the property.
i hope it helps
Iterate over the array and set index in object where match found
var categoryGroups = [{
Id : 1,
Categories : [{
Id : 1
}, {
Id : 2
},
]
}, {
Id : 2,
Categories : [{
Id : 100
}, {
Id : 200
},
]
}
]
var filterVal = [];
var needle = 100;
for (var i = 0; i < categoryGroups.length; i++) {
var subCategory = categoryGroups[i]['Categories'];
for (var j = 0; j < subCategory.length; j++) {
if (subCategory[j]['Id'] == findId) {
filterVal.push({
catIndex : i,
subCatIndex : j,
id : needle
});
}
}
}
console.log(filterVal);
Here is solution using reduce:
var arr = [{ Id: 1, Categories: [{ Id: 1 }, { Id: 2 }, ] }, { Id: 2, Categories: [{ Id: 100 }, { Id: 200 }, ] } ]
const findPositions = (id) => arr.reduce((r,c,i) => {
let indx = c.Categories.findIndex(({Id}) => Id == id)
return indx >=0 ? {mainIndex: i, categoryIndex: indx} : r
}, {})
console.log(findPositions(100)) // {mainIndex: 1, categoryIndex: 0}
console.log(findPositions(1)) // {mainIndex: 0, categoryIndex: 0}
console.log(findPositions(200)) // {mainIndex: 1, categoryIndex: 1}
console.log(findPositions(0)) // {}
Beside the given answers with fixt depth searh, you could take an recursive approach by checking the Categories property for nested structures.
function getPath(array, target) {
var path;
array.some(({ Id, Categories = [] }) => {
var temp;
if (Id === target) {
path = [Id];
return true;
}
temp = getPath(Categories, target);
if (temp) {
path = [Id, ...temp];
return true;
}
});
return path;
}
var array = [{ Id: 1, Categories: [{ Id: 1 }, { Id: 2 },] }, { Id: 2, Categories: [{ Id: 100 }, { Id: 200 }] }];
console.log(getPath(array, 100));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have problems in going through these two for loops, I need to get the same elements from the first array within the cycle, but the values are being repeated. I know that they are repeated depending on the data of the second array.
I tried to make comparisons but I could not get the result I want.
var array = [
{
grouper: 1
},
{
grouper: 2
},
{
grouper: 3
},
{
grouper: 4
},
];
var array2 = [
{
value: 1,
grouper: 1,
status: 100
},
{
value: 2,
grouper: 2,
status: 100
},
{
value: 3,
grouper: 3,
status: 100
}
];
for(var i = 0; i<array.length; i++){
for(var j = 0; j<array2.length; j++){
if(array2[j].grouper == array[i].grouper){
console.log(array[i].grouper+'-'+array2[j].value);
}
}
}
This is the result I want, I need all the groupers from the first array and the values from the second array:
1-1
2-2
3-3
4-
The grouper 4, does not have value, but I need to show it.
I need the second array because I'm going to compare with the data from the second array
I do not know if I am doing the process wrong. I hope you can help me.
You could simply track if there was a match (variable shown), and if there were not any, display a "half" line:
var array = [{grouper: 1},{grouper: 2},{grouper: 3},{grouper: 4},];
var array2 = [
{value: 1, grouper: 1, status: 100},
{value: 2, grouper: 2, status: 100},
{value: 3, grouper: 3, status: 100}
];
for(var i = 0; i<array.length; i++){
var shown=false;
for(var j = 0; j<array2.length; j++){
if(array2[j].grouper == array[i].grouper){
console.log(array[i].grouper+'-'+array2[j].value);
shown=true;
}
}
if(!shown){
console.log(array[i].grouper+"-");
}
}
First of all, with the example you provided I believe you want to get back:
1,2,3
There is no 4th object inside of array2, so your conditional (array2[j].grouper == array[i].grouper will never evaluate to true.
The question here is whether you are always comparing the same indexes? In this example, you're comparing array[0] to array2[0] to see if grouper in array equals grouper in array2... that's it????
In that case you just do one loop:
for (var i = 0; i < array.length; i++) {
if (array[i].grouper == array2[i].grouper) {
console.log(array[i].grouper+'-'+array2[j].value);
}
}
#FabianSierra ... with your provided example one just needs to handle the not fulfilled if clause/condition in the most inner loop.
A more generic approach additionally might take into account changing field names (keys). Thus a function and Array.reduce / Array.find based approach provides better code reuse. An example implementation then might look similar to that ...
var array = [{ // in order.
grouper: 1
}, {
grouper: 2
}, {
grouper: 3
}, {
grouper: 4
}];
var array2 = [{ // not in the order similar to `array`.
value: 22,
grouper: 2,
status: 200
}, {
value: 33,
grouper: 3,
status: 300
}, {
value: 11,
grouper: 1,
status: 100
}];
function collectRelatedItemValuesByKeys(collector, item) {
var sourceKey = collector.sourceKey;
var targetKey = collector.targetKey;
var targetList = collector.targetList;
var resultList = collector.result;
var sourceValue = item[sourceKey];
var targetValue;
var relatedItem = targetList.find(function (targetItem) {
return (targetItem[sourceKey] === sourceValue);
});
if (typeof relatedItem !== 'undefined') {
targetValue = relatedItem[targetKey];
} else if (typeof targetValue === 'undefined') {
targetValue = ''; // `relatedItem` does not exist.
}
resultList.push([sourceValue, targetValue].join('-'));
return collector;
}
var resultList = array.reduce(collectRelatedItemValuesByKeys, {
sourceKey: 'grouper',
targetKey: 'value',
targetList: array2,
result: []
}).result;
console.log('resultList : ', resultList);
resultList = array.reduce(collectRelatedItemValuesByKeys, {
sourceKey: 'grouper',
targetKey: 'status',
targetList: array2,
result: []
}).result;
console.log('resultList : ', resultList);
.as-console-wrapper { max-height: 100%!important; top: 0; }
I'm working with a list of HTML headers (h2,h3,h4,h5,h6).
The picture describes the idea:
[
{
text: 'Some header',
rank: 2, // stays for <h2>
},
{
text: 'Some another header',
rank: 3, // stays for <h3>
},
{
text: 'A header with the same rank',
rank: 3, // stays for <h3>
},
{
text: 'One more subsection header',
rank: 4, // stays for <h4>
}
]
And I'm trying to turn it into a tree:
[
{
text: 'Some header',
children: [
{
text: 'Some another header',
},
{
text: 'A header with the same rank',
children: [
{
text: 'One more subsection header',
}
]
}
]
}
]
Here's my current code:
function list_to_tree(list) {
// We go from the end to the beggining
list = list.reverse();
let node, nextNode, roots = [], i;
for (i = 0; i < list.length; i += 1) {
node = list[i];
nextNode = list[i+1];
// If the next one's rank is greater, the current into the next as a child
if (nextNode !== undefined && node.rank > nextNode.rank) {
list[i+1].children.push(node);
} else {
// Else it's a root
roots.push(node);
}
}
return roots;
};
But it works only for the first h3, but the second h3 will go as a root. Any idea on how to achieve the goal? Thank you.
You could use the level property rank for indicating the nested position in a helper array.
Then iterate the data and build children arrays, if necessary.
function getTree(array) {
var levels = [{}];
array.forEach(function (o) {
levels.length = o.rank;
levels[o.rank - 1].children = levels[o.rank - 1].children || [];
levels[o.rank - 1].children.push(o);
levels[o.rank] = o;
});
return levels[0].children;
}
var data = [{ text: 'Main Heading', rank: 1 }, { text: 'Sub Heading', rank: 2 }, { text: 'Sub Sub Heading', rank: 3 }, { text: 'Sub Heading', rank: 2 }, { text: 'Sub Sub Heading', rank: 3 }, { text: 'Sub Sub Heading', rank: 3 }];
console.log(getTree(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This solution will work irrespective of starting rank and also of the order in which the list is given... and it uses the exact data you provided...
var jsonHeaders =
[
{
text: 'Some header',
rank: 2, // stays for <h2>
},
{
text: 'Some another header',
rank: 3, // stays for <h3>
},
{
text: 'A header with the same rank',
rank: 3, // stays for <h3>
},
{
text: 'One more subsection header',
rank: 4, // stays for <h4>
}
];
function list_to_tree(list)
{
var jsonTree = [{}];
list = list.reverse();
for (i = 0, l = list.length; i < l; i++)
{
node = list[i];
var json = {};
json.text = node.text;
json.rank = node.rank;
if(jsonTree[0].rank == undefined)
{
jsonTree[0] = json;
}
else
if(jsonTree[0].rank == json.rank)
{
jsonTree.push(json);
}
else
if(jsonTree[0].rank < json.rank)
{
jsonTree[0] = ranker(jsonTree[0], json);
}
else
if(jsonTree[0].rank > json.rank)
{
var jsonTemp = jsonTree[0];
jsonTree[0] = json;
json = jsonTemp;
jsonTree[0] = ranker(jsonTree[0], json);
}
}
return jsonTree;
}
function ranker(jsonTree, json)
{
if(jsonTree.children == undefined)
{
jsonTree.children = [];
jsonTree.children.push(json);
}
else
if(jsonTree.children[0].rank == json.rank)
{
jsonTree.children.push(json);
}
else
if(jsonTree.children[0].rank < json.rank)
{
jsonTree.children[0] = ranker(jsonTree.children[0], json);
}
else
if(jsonTree.children[0].rank > json.rank)
{
var jsonTemp = jsonTree;
jsonTree = json;
json = jsonTemp;
jsonTree.children[0] = ranker(jsonTree.children[0], json);
}
return jsonTree;
}
var jsonTree = list_to_tree(jsonHeaders);
console.log('jsonArrayTree = ', jsonTree);
Here's the working function in case someone needs it:
function list_to_tree(list) {
list = list.reverse();
let node, currentRank = list[0].rank, i, roots = [];
for (i = 0; i < list.length; i += 1) {
node = list[i];
if (node.rank > currentRank) {
for (let n = i; n < list.length; n += 1) {
if (list[n].rank < node.rank) {
list[n].children.unshift(node);
break;
}
}
} else {
currentRank = node.rank;
roots.push(node);
}
}
return roots.reverse();
};