In my Javascript program, I have a list of Person objects.
For example
[
"Michael": {
"age": 45,
"position": "manager",
...
},
"Dwight": {
"age": 36,
"position": "assistant manager",
...
},
....
]
I want to find the youngest Person.
I've accomplished this by creating two arrays: one of all the Persons and one of all their ages, and getting the index of the lowest age and applying it to the first array. Like:
var arrayOfPersons = [persons[0], persons[1], ....];
var arrayOfAges = [persons[0].age, persons[1].age, ....];
var min = arrayOfAges.indexOf(Math.max.apply(Math, arrayOfAges));
var youngestPerson = arrayOfPerson[min];
The problem with this is it is inefficient doesn't seem like the best way. Also it doesn't deal with the fact that there may be a tie for youngest.
Does anyone know of a more native, simpler way to do this?
You can sort the persons array by age property and pick first one:
var persons = [
{ name: 'Michael', age: 45, position: 'manager' },
{ name: 'Dwight', age: 36, position: 'assistant manager' },
{ name: 'Foo', age: 99, position: 'foo' },
{ name: 'Bar', age: 37, position: 'bar' }
];
persons.sort(function(a, b) {
return a.age > b.age;
});
console.log('Youngest person: ', persons[0]);
Related
I have a problem with a task, I have to count the highest level in a structure which looks like this:
let node = {
age: 23,
name: "christian",
children: [{
age: 25,
name: "michael",
children: [{
age: 33,
name: "Johann",
children: [{
age: 45,
name: "Christiaaann",
}]
}]
}, {
age: 90,
name: "Monika",
children: [{
age: 10,
name: "WHATEVER",
}]
}]
};
The level of the first subtree would be 3 as it contains 3 nested children arrays.
The right level would be 2 as it contains 2 nested children arrays.
I tried to solve it recursively, and of course I know that I have to count the level of each subtree and then check it with a condition if it is greater than the previous maximum.
My problem is that I don't know where to count it up in the recursive call.
This is my solution, so far
let node = {
age: 23,
name: "christian",
children: [{
age: 25,
name: "michael",
children: [{
age: 33,
name: "Johann",
children: [{
age: 45,
name: "Christiaaann",
}]
}]
}, {
age: 90,
name: "Monika",
children: [{
age: 10,
name: "WHATEVER",
}]
}]
};
let level_count;
let max_count = 0;
function level_counter(obj, func) {
level_count = 0;
func(obj);
console.log("INSIDEFUNCTION", level_count);
if (obj.children) {
level_count++;
obj.children.forEach(function(child) {
console.log(child);
level_counter(child, func);
});
if (level_count > max_count) {
max_count = level_count;
}
}
}
function tree_get_levels(root) {
level_counter(root, function(obj) { });
console.log("DOWNONE", level_count);
return 0;
}
let result = tree_get_levels(node);
console.log(result);
I tried to solve it recursively, and of course I know that I have to count the level of each subtree and then check it with a condition if it is greater than the previous maximum.
My problem is that I don't know where to count it up in the recursive call.
You need to use the return value of the recursive call, adding one for the level making the call to it. Separately, always avoid global variables when you're trying to write a recursive solution; every level of recursion sees the same values for those variables, and assigning to them won't work correctly. Stick to variables defined within the recursive function, and (again) report values back up the stack by returning them.
See inline notes in the code:
let node = {
age: 23,
name: "christian",
children: [{
age: 25,
name: "michael",
children: [{
age: 33,
name: "Johann",
children: [{
age: 45,
name: "Christiaaann",
}]
}]
}, {
age: 90,
name: "Monika",
children: [{
age: 10,
name: "WHATEVER",
}]
}]
};
function countLevels(obj, func) {
// No levels so far
let levelCount = 0;
func(obj); // Not sure what this function is for
// If there are any children...
if (obj.children) {
// There are, so we've already gone one level down
for (const child of obj.children) {
// Get levels starting at this child, then add one because we've
// already gone one level down
const levelsFromChild = countLevels(child, func) + 1;
// Remember it if it's higher than the maximum we've seen
if (levelCount < levelsFromChild) {
levelCount = levelsFromChild;
}
// Or that could be replaced with:
// levelCount = Math.max(levelCount, countLevels(child, func) + 1);
}
}
// I added this so you could see the levels count starting from each object
console.log(`${levelCount} level(s) from ${JSON.stringify(obj)}`);
// Return the levels found from this object
return levelCount;
}
// No need for a separate wrapper function, just call the counter directly
let result = countLevels(node, function func(obj) { });
console.log(`Deepest: ${result}`);
.as-console-wrapper {
max-height: 100% !important;
}
You can try this:
function highestDepth(obj) {
let depth = 0;
if (Array.isArray(obj.children) && obj.children.length) {
depth += 1;
let subDepth = 0;
for (const child of obj.children) {
subDepth = Math.max(subDepth, highestDepth(child));
}
depth += subDepth;
}
return depth;
}
console.log(highestDepth(node));
A simple recursive version first checks whether the node has children. If it doesn't, we simply return 0; if it does, we recur over each of its children, and take the maximum of those (or 0 if the children array is empty) and add 1. It looks like this:
const maxDepth = (node) => 'children' in node
? 1 + Math .max (0, ... node .children .map (maxDepth))
: 0
const node = {age: 23, name: "christian", children: [{age: 25, name: "michael", children: [{age: 33, name: "Johann", children: [{age: 45, name: "Christiaaann"}]}]}, {age: 90, name: "Monika", children: [{age: 10, name: "WHATEVER"}]}]}
console .log (maxDepth (node))
The 0 passed as the first parameter to Math .max is necessary because Math .max () (with no parameters) returns -Infinity. It's an interesting exercise to try to figure out why that is.
Here is an iterative solution using object-scan. This solution will work even when you are dealing with very deeply nested object hierarchies.
.as-console-wrapper {max-height: 100% !important; top: 0}
<script type="module">
import objectScan from 'https://cdn.jsdelivr.net/npm/object-scan#18.4.0/lib/index.min.js';
const node = { age: 23, name: 'christian', children: [{ age: 25, name: 'michael', children: [{ age: 33, name: 'Johann', children: [{ age: 45, name: 'Christiaaann' }] }] }, { age: 90, name: 'Monika', children: [{ age: 10, name: 'WHATEVER' }] }] };
const fn = objectScan(['**{children[*]}'], {
rtn: 'count', // for performance
beforeFn: (state) => {
state.context = { depth: 0 };
},
filterFn: ({ context, depth }) => {
context.depth = Math.max(context.depth, depth);
},
afterFn: ({ context }) => context.depth / 2
});
console.log(fn(node));
// => 3
</script>
Disclaimer: I'm the author of object-scan
I have an array of objects, each with various properties. I want to check if one particular property is equal across all of the objects. e.g.
peopleArr = [
{
name: Simon,
age: 22,
hair: brown
},
{
name: John,
age: 22,
hair: black
},
{
name: James,
age: 22,
hair: blond
}
]
I need a function that returns true if age has the same value across all of the objects in the array, and false if not. I've tried some variations using .every, but can't get it to work with object properties specifically (I'm relatively new). Any help appreciated.
You can use array every method and inside the callback check if age in all the object is equal to 22. It will return Boolean value and it will return true if all all the object matches the condition
const peopleArr = [{
name: 'Simon',
age: 22,
hair: 'brown'
},
{
name: 'John',
age: 22,
hair: 'black'
},
{
name: 'James',
age: 23,
hair: 'blond'
}
]
const res = peopleArr.every(item => item.age === 22);
console.log(res)
An alternative to using the .every() method, would be to filter the array and compare the filtered array length to the original array length. Like so
const peopleArr = [
{
name: "Simon",
age: 22,
hair: "brown"
},
{
name: "John",
age: 22,
hair: "black"
},
{
name: "James",
age: 22,
hair: "blond"
}
]
const array_val_same = ( arr, val ) => {
let filtered = arr.filter(el => el.age === val)
return filtered.length === arr.length ? true : false
}
array_val_same(peopleArr, 22)
This is just an alternative, i'd still use .every() though.
I have a large JSON response that I get back after an HTTP call that looks like this:
0: { index: 0, name: "bob", age: 12, location: "adelaide" ... }
1: { index: 0, name: "jeff", age: 23 ... }
2: { index: 1, name: "sam", age: 25 ... }
...
From this, I want to create an array of objects, with one object for each value of index and its corresponding entries, where I can choose what data goes into those entries. Something like this:
[
{ name: "index_0", index: 0, data: [{ name: "bob", age: 12 }, { name: "jeff", age: 23 }] },
{ name: "index_1", index: 1, data: [{ name: "sam", age: 25 }] },
...
]
I know I need to create objects dynamically here based on the index count, but I'm not sure how to do this.
const newdata = [];
origdata.forEach(function(item){
if(!newdata[item.index])
newdata[item.index] = {name:'index_'+item.index,index:item.index,data:[]};
newdata[item.index].data.push(item);
delete item.index;
});
First array
userData = [
{ name: abc, age: 24 },
{ name: ghi, age: 22 },
{ name: tyu, age: 20 }
];
Second array
userAge = [
{ age: 25 },
{ age: 26 },
{ age: 22 }
];
Both arrays have the same length.
How do I update the useData[0].age with userAge[0] using Underscore.js?
Since you need to do this over a list of dictionaries, you will need to iterate over the list using _.each.
Something like this will help,
_.each(userData, function(data, index) {
data.age = userAge[index].age;
});
While #martianwars is correct, it could be a little more generic, thus more useful, if it could apply any attribute.
Say we have an array of changes to apply, with each not being necessarily the same attribute or even multiple attributes per object:
var changes = [
{ age: 25 },
{ name: "Guy" },
{ name: "Pierre", age: 22 }
];
Changes could be applied with _.extendOwn
_.each(userData, function(data, index) {
_.extendOwn(data, changes[index]);
});
Proof of concept:
var userData = [{
name: "abc",
age: 24
}, {
name: "ghi",
age: 22
}, {
name: "tyu",
age: 20
}];
var changes = [{
age: 25
}, {
name: "Guy"
}, {
name: "Pierre",
age: 22
}];
_.each(userData, function(data, index) {
_.extendOwn(data, changes[index]);
});
console.log(userData);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
This will only work if the arrays are in sync. Meaning that if there are 4 objects in the userData array, and only 3 changes, they need to be at the right index and that could become a problem.
A solution to this is to have an identification property, often represented by an id attribute.
userData = [
{ id: '1', name: 'abc', age: 24 },
{ id: '2', name: 'ghi', age: 22 },
{ id: '3', name: 'tyu', age: 20 }
];
See Merge 2 objects based on 1 field using Underscore.js for details.
i have two arrays variables in which each element is an object having some properties like this :
var employees = [{
name: 'Jack',
empId: 0,
age: 25,
orgId: 1
}, {
name: 'Lucifer',
empId: 1,
age: 35,
orgId: 2
}, {
name: 'Adam',
empId: 3,
age: 46,
orgId: 1
}, {
name: 'Eve',
empId: 4,
age: 30,
orgId: 3
}];
and the second variable is
var companies= [{
name: 'Microsoft',
id: 1,
employees: [5 , 9]
}, {
name: 'Google',
id: 2,
employees: [1]
}, {
name: 'LinkedIn',
id: 3,
employees: [10]
}];
so now i want that when i give a company name (for example: Google),then it will return the employee details. i want to do it by using filter()/reduce() method, but i am not able to do it . Help needed .. thank you
If the employee orgId is the same as the company id you can use filter; one to get the id, and then another to grab the employees associated with that id. The function returns an array of employees.
function getEmployees(company) {
var id = companies.filter(function (el) {
return el.name === company;
})[0].id;
return employee.filter(function (el) {
return el.orgId === id;
});
}
getEmployees('Microsoft');
OUTPUT
[
{
"name": "Jack",
"empId": 0,
"age": 25,
"orgId": 1
},
{
"name": "Adam",
"empId": 3,
"age": 46,
"orgId": 1
}
]
DEMO
You can do that with a forEach loop and checking the name:
var Employees = []; //initialize
companies.forEach(function(company) {
if (company.name == "Microsoft"){
Employees = company.employees;
//whatever you like
Employees.forEach(function(id){
alert(id);
});
}
});
Working JsFiddle: https://jsfiddle.net/sapyt777/
Trying to brush-up my skills. So I'm pretty sure it works but I don't know if it's a good way to achieve what you want!
var input = "Microsoft";
for(company in companies) {
if(companies[company].name === input) {
for(emp in employee) {
if(companies[company].id === employee[emp].orgId)
{
console.log(employee[emp]);
}
}
}
}