I have an array of objects. A typical object looks like:
{
id: x
name: y
employeeInfo: {
employeeNumber: x
startDate: x
}
salary: x
}
Now I'm trying to loop through it and get the name, employeeNumber and salary.
My column variable, to be used in the loop, is:
public columns: Array<any> = [
{title: 'id', name: 'id'},
{title: 'employeeInfo.employeeNumber', name: 'employeeInfo.employeeNumber'},
{title: 'salary', name: 'salary'}]
I'm trying to loop with
item[column.name]
but of course this would result in item['emplyeeInfo.employeeNumber'], which would result in a undefined.
Can someone help?
You can split the column name and reduce, like:
column.name.split('.').reduce((res, part) => res[part], item)
split returns an array (in our case ['employeeInfo', 'employeeNumber']) so we can reduce that array using the item as the initialValue.
The reduce() method applies a function against an accumulator and each
element in the array (from left to right) to reduce it to a single
value.
Something like this:
var employees = [
{
id: 1,
name: 'Charlie',
employeeInfo: {
employeeNumber: 123,
startDate: '2017-01-23'
},
salary: 2500
},
{
id: 2,
name: 'John',
employeeInfo: {
employeeNumber: 456,
startDate: '2017-02-26'
},
salary: 3500
}
];
var columns = [
{title: 'id', name: 'id'},
{title: 'employeeInfo.employeeNumber', name: 'employeeInfo.employeeNumber'},
{title: 'salary', name: 'salary'}
];
function buildTable() {
var table = $("<table>");
var header = $("<tr>");
for(var i = 0; i < columns.length; i++) {
header.append("<th>" + columns[i].title + "</th>");
}
table.append(header);
for(var i = 0; i < employees.length; i++) {
var employee = employees[i];
var row = $("<tr>");
for(var y = 0; y < columns.length; y++) {
var properties = columns[y].name.split('.');
var value = employee;
for(var x = 0; x < properties.length; x++) {
value = value[properties[x]];
}
row.append("<td>" + value + "</td>");
}
table.append(row);
}
$("#result").append(table);
}
buildTable();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result"></div>
Can't you just parse/split the name on the dot and for each part, you get the object, fetch its property and reiterate while there is a next property to fetch?
I ended up using a "simplify" approach. i.e. filter through the array, grab what I need, put it in a new object, put it in a temporary array and finally replace the complex array with the simple array.
try this:
var myObject = {
id: "x",
name: "y",
employeeInfo: {
employeeNumber: "inner employeeNumber",
startDate: "inner date",
},
salary: "x"
}
for(var id in myObject) {
if(typeof myObject[id] === "object") {
for(var innerId in myObject[id]){
console.log(innerId + ": " + myObject[id][innerId]);
}
} else {
console.log(id + " " + myObject[id]);
}
}
Related
I'm kinda new to javascript. Here I have the following object:
obj = {
0:{id:1, location: loc1, title:title1},
1:{id:2, location: loc2, title:title2},
2:{id:3, location: loc1, title:title3},
3:{id:4, location: loc3, title:title4},
4:{id:5, location: loc1, title:title5}
}
What I need is to filter the object by location depending on its value and create a new object like the following:
obj = {
loc1:{
0:{id:1, location: loc1, title:title1},
1:{id:3, location: loc1, title:title3},
2:{id:5, location: loc1, title:title5}
},
loc2:{
0:{id:2, location: loc2, title:title2}
}
loc3:{
0:{id:4, location: loc3, title:title4}
}
}
How can I achieve the above object?
I tried using for and push to a new array but the location should be dynamic and may change in the future and I want to have one object to manage like above.
var theLoc1 = [], theLoc2 = [];
for(var i = 0; i < response.length; i++) {
if(response[i].location == 'loc1'){
theLoc1.push(response[i]);
}else if(response[i].location == 'loc2'){
theLoc2.push(response[i]);
}
}
This Code is what u really need:
obj = [
{ id: 1, location: 'loc1', title: 'title1' },
{ id: 2, location: 'loc2', title: 'title2' },
{ id: 3, location: 'loc1', title: 'title3' },
{ id: 4, location: 'loc3', title: 'title4' },
{ id: 5, location: 'loc1', title: 'title5' }
];
var locations = {};
for (var i = 0; i < obj.length; i++) {
locations[obj[i].location] = [];
}
console.log(locations);
for (var i = 0; i < obj.length; i++) {
locations[obj[i].location].push(obj[i]);
}
console.log(locations);
**Update:It Can be done in a single for loop but for simplicity reasons i wrote it like this. **
let obj;
for(var i = 0; i < response.length; i++) {
if( !Object.hasOwnProperty(obj, response[i].location)
{ obj[response[i].location] = []; }
obj[response[i].location].push(response[i]);
}
You can dynamically create JS object properties if you just address them. This means:
let obj = {};
obj.bark = "how-how";
console.log(obj.bark); // "how-how";
obj[bark2] = "waf-waf";
console.log(obj.bark2); // "waf-waf";
you can use it to struct your new object with the locations names, so even if someday you get "location999" it'll still work.
I put the if that checks if the object laready has that property because you want the property to be an array. If it wasn't you could've just put the value inside like in my example, but im not sure if push would work on it so I initialize it to be empty array just in case. You can check it yourself and ommit the if if its not needed.
My solution using functional programming.
const obj = {
0: { id: 1, location: 'loc1', title: 'title1' },
1: { id: 2, location: 'loc2', title: 'title2' },
2: { id: 3, location: 'loc1', title: 'title3' },
3: { id: 4, location: 'loc3', title: 'title4' },
4: { id: 5, location: 'loc1', title: 'title5' }
};
const result = Object.keys(obj).reduce((newObject, item) => {
const location = obj[item].location;
const index = newObject[location] ? Object.keys(newObject[location]).length : 0;
return {
...newObject,
[location]: {
...newObject[location],
[index]: obj[item]
}
};
}, {});
console.log(result);
In order to group your items by location you can iterate your array, see whether its location was already grouped and if not, create a new group for it. Afterwards add the item to the corresponding group.
var obj = [
{id: 1, location: "loc1", title: "title1"},
{id: 2, location: "loc2", title: "title2"},
{id: 3, location: "loc1", title: "title3"},
{id: 4, location: "loc3", title: "title4"},
{id: 5, location: "loc1", title: "title5"}
];
var formattedArray = new Array();
for (var i = 0; i < obj.length; i++) {
if (!formattedArray[obj[i].location]) {
formattedArray[obj[i].location] = new Array();
}
formattedArray[obj[i].location].push(obj[i]);
}
console.log(formattedArray);
JsFiddle example code:
JsFiddle
You can try the following if your loc1, loc2, loc3 are fixed. (That is what I understood after reading your query)
var response = [
{id:1, location: "loc1", title:"title1"},
{id:2, location: "loc2", title:"title2"},
{id:3, location: "loc1", title:"title3"},
{id:4, location: "loc3", title:"title4"},
{id:5, location: "loc1", title:"title5"}
]
var resObj = {
published:[],
private: [],
pending:[]
}
for(var i = 0; i < response.length; i++) {
if(response[i].location == 'loc1'){
resObj.published.push(response[i]);
}else if(response[i].location == 'loc2'){
resObj.private.push(response[i]);
}else {
resObj.pending.push(response[i]);
}
}
console.log(resObj)
I think the better way to do this, is to group your objects already in your backend. You can use the linq function .GroupBy(x => x.location).
This is near the same problem:
How to count rows of a table grouped by shortdatestring?
// create an array of arrays;
var groupOfLocations[];
// loop on your locations
for(var i = 0; i < response.length; i++) {
// push if already existing
for(var iGroup = 0; iGroup < groupOfLocations.length; iGroup++) {
if(groupOfLocations[iGroup][0].location == response[i].location) {
groupOfLocations[iGroup].push(response[i]); break;
}
// create a new array if not found
if(iGroup >= groupOfLocations.length) groupOfLocations.push(new array(response[i]));
}
May contains syntax mistakes, but the idea is here.
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 have an array of name/value objects (below). The names are formatted to represent multi-dimensional array.
I need to build a full JavaScript object out of it(bottom).
[{
name: "getQuote[origin]",
value: "Omaha,NE"
},
{
name: "getQuote[destination]",
value: "10005"
},
{
name: "getQuote[country]",
value: "us"
},
{
name: "getQuote[vehicles][0][year]",
value: "1989"
},
{
name: "getQuote[vehicles][0][make]",
value: "Daihatsu"
},
{
name: "getQuote[vehicles][0][model]",
value: "Charade"
},
{
name: "getQuote[vehicles][0][count]",
value: "1"
}]
Into something like this:
{getQuote :
{ origin : Omaha},
{ destination : 10005},
{vehicles : [
{
year : 1989,
make: Honda,
model : accord
},
{
//etc
}]
n
You can do it manually, like this:
var source = [ /* Your source array here */ ];
var dest = {};
for(var i = 0; i < source.length; i++)
{
var value = source[i].value;
var path = source[i].name.split(/[\[\]]+/);
var curItem = dest;
for(var j = 0; j < path.length - 2; j++)
{
if(!(path[j] in curItem))
{
curItem[path[j]] = {};
}
curItem = curItem[path[j]];
}
curItem[path[j]] = value;
}
dest is the resulting object.
Check it working here: http://jsfiddle.net/pnkDk/7/
I have an array of javascript objects like the following:
var food = [
{id: 1, name: 'Apples', owned: true },
{id: 2, name: 'Oranges', owned: false },
{id: 3, name: 'Bananas', owned: true }
];
Then I receive another array with the following data:
var newFood = [
{id: 1, name: 'Peas'},
{id: 2, name: 'Oranges'},
{id: 3, name: 'Bananas'},
{id: 4, name: 'Grapefruits'}
];
How can I update the previous food array with the new information in newFeed, without overwriting the original owned property, while adding an owned: false to any new object?
Keep in mind this is plain javascript, not jQuery.
You'd probably want to index food by id so make food an object instead of an array:
var food = {
1: {name: "Apples", owned: true},
//...
}
then iterate over newFood and update the fields appropriately.
I think you can use underscore.js for fix the problem.
var arrayObj = [
{Name:'John',LastName:'Smith'},
{Name:'Peter',LastName:'Jordan'},
{Name:'Mike',LastName:'Tyson'}
];
var element = _.findWhere(arrayObj, { Name: 'Mike' });
element.Name="SuperMike";
console.log(arrayObj);
This works:
var temp = {};
for (var i = 0, l = food.length; i < l; i += 1) {
temp[food[i].name] = true;
}
for (var i = 0, l = newFood.length; i < l; i += 1) {
if ( !temp[newFood[i].name] ) {
food.push( { id: food.length + 1, name: newFood[i].name, owned: false });
}
}
The first for statement will populate the temp object with the fruit names from the food array, so that we know which fruits exist in it. In this case, temp will be this:
{ "Apples": true, "Oranges": true, "Bananas": true }
Then, the second for statement checks for each fruit in newFood if that fruit exists in temp, and if it doesn't, if pushes a new array item into the food array.
some thing like this? JSFiddle Example
JavaScript
function updateFood( newFood, oldFood ) {
var foodLength = oldFood.length - 1;
for (var i = 0; i < newFood.length; i++) {
if (i > foodLength) { //add more if needed
newFood[i].owned = false;
oldFood.push(newFood[i]);
} else if (!food[i].owned) { //replace if needed
newFood[i].owned = false;
oldFood[i] = newFood[i];
}
}
}