Mapping an org chart into a hash table - javascript

Hey all I'm trying to take an array of objects(employees) and map them to a new object in order to depict the hierarchy of the org. So each manager would have a key and an array attached to the key holding all the names of their reports.
I'm unsure why I am unable to push my employee names to their respective manager's array. This seems to set my object keys to arrays rather than 1,2,3,4.
Anyone pointers would be appreciated.
Repl.it: https://repl.it/JeMh/2
let data = [
{
name: 'ceo',
id: 1,
mgr: null,
},
{
name: 'vp1',
id: 2,
mgr: 1,
},
{
name: 'vp2',
id:3,
mgr: 1,
},
{
name: 'mgr',
id:4,
mgr: 2,
},
];
function displayOrg(data) {
let org = {};
for(let i = 0; i < data.length; i++) {
let current = data[i];
for(let key in current){
if(org[key] !== current.id || current.mgr){
org[current.id] = []
}
}
for(let key in org){
console.log(current.mgr);
console.log(org[key])
if(current.mgr === org[key]){
console.log("THIS HAPPEN");
org[key].push(current.name);
}
}
}
return org;
}
displayOrg(data);
expected resulted: { '1': [vp1,vp2], '2': [mgr], '3': [], '4': [] }

looks pretty straight forward:
function getMngd(data, mngrId){
return data.filter(emp => emp.mgr === mngrId).map(emp => emp.name)
}
data.reduce((p,c)=>{
const {id} = c;
p[id] = getMngd(data, id);
return p;
},{})

Related

How to add label to js array?

Hi I am looking to create an array that looks similar to this
const userList = {
123: "Tom",
124: "Michael",
125: "Christin",
};
it contains both value and label, what I tried so far
let raw = []
for (let x in data) {
raw.push(data[x].facility_name : data[x].id)
}
but it didn't work because "," was expected, if someone can help please
You are confusing arrays and objects. You need to add a key to an object not push. I kept it as a for in loop, but a for of loop would make more sense.
const data = [
{ id: 1, facility_name: "foo1" },
{ id: 2, facility_name: "foo2" },
{ id: 3, facility_name: "foo3" }
];
let raw = {};
for (let x in data) {
raw[data[x].id] = data[x].facility_name;
}
console.log(raw);
How I would code it using reduce.
var data = [
{ id: 1, facility_name: "foo1" },
{ id: 2, facility_name: "foo2" },
{ id: 3, facility_name: "foo3" }
];
const raw = data.reduce(function (acc, facility) {
acc[facility.id] = facility.facility_name;
return acc;
}, {})
console.log(raw);
IF your data has nested objects then you might do this:
let raw = {};
for(x in data)
{
raw[data[x].facility_name] = data[x].id;
}
This is useful when you want to get rid of duplicates.

Remove entire key when matched with matched array values

I am new to react, I have an object and an array, I want to get details of unmatched items from the object when compared with array values. I tried but shows all the data when consol.log. here is my code
var content:[
0:{id:20, name:'Jack Daniel'}
1:{id:21, name:'Sophie McDonald'}
2:{id:22, name:'Jason Thomas'}
3:{id:23, name:'Chris Williams'}
]
var filter:[Sophie McDonald, Chris Williams]
filterValues = content.filter(item=> {
for(var i = 0;i<filter.length;i++) {
if (item.name === filtered[i])
{
return item
}
}
});
console.log(filteredValues)
// returns 0:{id:21, name:'Sophie McDonald'}
// 1:{id:23, name:'Chris Williams'}
But I need unmatched results,
filterValues = content.filter(item=> {
for(var i = 0;i<filter.length;i++) {
if (item.name !== filtered[i])
{
return item
}
}
});
console.log(filteredValues)
// returns 0:{id:20, name:'Jack Daniel'}
// 1:{id:21, name:'Sophie McDonald'}
// 2:{id:22, name:'Jason Thomas'}
// 3:{id:23, name:'Chris Williams'}
Result must be
0:{id:20, name:'Jack Daniel'}
1:{id:22, name:'Jason Thomas'}
Try using filter, checking if the values of the array are present in your object values:
const content = [{
id: 20,
name: 'Jack Daniel'
},
{
id: 21,
name: 'Sophie McDonald'
},
{
id: 22,
name: 'Jason Thomas'
},
{
id: 23,
name: 'Chris Williams'
}
];
const values = ['Sophie McDonald', 'Chris Williams'];
const filteredValues = content.filter(({
name
}) => !values.includes(name));
console.log(filteredValues);
Seems to work with a few edits to the format:
let content = [
{id:20, name:'Jack Daniel'},
{id:21, name:'Sophie McDonald'},
{id:22, name:'Jason Thomas'},
{id:23, name:'Chris Williams'}
]
let filter = ["Sophie McDonald", "Chris Williams"]
let filterValues = content.filter(item=> {
for(var i = 0;i<filter.length;i++) {
if (item.name !== filter[i]){
return item
}
}
});
console.log(filterValues)

Finding objects in a nested array along with their position

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; }

Trying to avoid duplicates when creating new array from comparing value of two others

I have an app where I need to create a new array by pushing values from two other arrays after comparing what values in one array exist in another.
Example:
From these two arrays...
sel[1,4];
bus[1,2,3,4,5,6];
The desired result is a new object array which will populate a repeater of checkboxes in my view...
newList[{1:true},{2:false},{3:false},{4:true},{5:false},{6:false}];
The problem I'm running into, is that my code is creating duplicates and I'm not seeing why.
Here is my code:
var newList = [];
var bus = self.businesses;
var sel = self.campaign.data.businesses;
for( var b = 0; b < bus.length; b++ ){
if(sel.length > -1){
for( var s = 0; s < sel.length; s++){
if( bus[b]._id === sel[s].business_id){
newList.push({'business_id':bus[b]._id, 'name':bus[b].business_name, 'selected':true});
} else {
newList.push({'business_id':bus[b]._id, 'name':bus[b].business_name, 'selected':false});
}
}
} else {
console.log('hit else statement');
newList.push({'business_id':bus[b]._id, 'name':bus[b].business_name, 'selected':false});
}
}
I need fresh eyes on this as it looks correct to me... but obviously I'm missing something. :-)
Your code produces duplicates because you push selected: false objects into your newList every time the inner loop is run and the ids don't match:
for( var s = 0; s < sel.length; s++){
if( bus[b]._id === sel[s].business_id){
newList.push({'business_id':bus[b]._id, 'name':bus[b].business_name, 'selected':true});
} else {
// THIS LINE CAUSES THE DUPLICATES:
newList.push({'business_id':bus[b]._id, 'name':bus[b].business_name, 'selected':false});
}
}
To fix your code, move this line out of the inner loop into the outer loop below and add a continue outer; to the inner loop's if body. Then you need to place the outer label directly in front of the outer loop: outer: for( var b = 0; b < bus.length; b++ ) ....
However, I recommend a simpler implementation as follows:
let selection = [{_id: 1, business_name: 'A'}];
let businesses = [{_id: 1, business_name: 'A'}, {_id: 2, business_name: 'B'}];
let result = businesses.map(business => ({
'business_id': business._id,
'name': business.business_name,
'selected': selection.some(selected => business._id == selected._id)
}));
console.log(result);
Appendix: Same implementation with traditional functions:
var selection = [{_id: 1, business_name: 'A'}];
var businesses = [{_id: 1, business_name: 'A'}, {_id: 2, business_name: 'B'}];
var result = businesses.map(function(business) {
return {
'business_id': business._id,
'name': business.business_name,
'selected': selection.some(function(selected) { return business._id == selected._id })
};
});
console.log(result);
I suggest to use a different approach by using an object for sel and the just iterate bus for the new array with the values.
function getArray(items, selected) {
var hash = Object.create(null);
selected.forEach(function (a) {
hash[a] = true;
});
return items.map(function (a) {
var temp = {};
temp[a] = hash[a] || false;
return temp;
});
}
console.log(getArray([1, 2, 3, 4, 5, 6], [1, 4]));
ES6 with Set
function getArray(items, selected) {
return items.map((s => a => ({ [a]: s.has(a) }))(new Set(selected)));
}
console.log(getArray([1, 2, 3, 4, 5, 6], [1, 4]));
You can use map() method on bus array and check if current value exists in sel array using includes().
var sel = [1,4];
var bus = [1,2,3,4,5,6];
var result = bus.map(e => ({[e] : sel.includes(e)}))
console.log(result)
This combines both Nina Scholz elegant ES6 approach with le_m's more specific solution to give you something that is shorter, versatile, and repurposable.
function getArray(items, selected, [...id] = selected.map(selector => selector._id)) {
return [items.map((s => a => ({
[a._id + a.business_name]: s.has(a._id)
}))(new Set(id)))];
}
console.log(...getArray([{
_id: 1,
business_name: 'A'
}, {
_id: 2,
business_name: 'B'
}, {
_id: 3,
business_name: 'C'
}, {
_id: 4,
business_name: 'D'
}, {
_id: 5,
business_name: 'E'
}, {
_id: 6,
business_name: 'F'
}], [{
_id: 1,
business_name: 'A'
}, {
_id: 2,
business_name: 'B'
}]));

Create new array from iterating JSON objects and getting only 1 of its inner array

See jsfiddle here: https://jsfiddle.net/remenyLx/2/
I have data that contains objects that each have an array of images. I want only the first image of each object.
var data1 = [
{
id: 1,
images: [
{ name: '1a' },
{ name: '1b' }
]
},
{
id: 2,
images: [
{ name: '2a' },
{ name: '2b' }
]
},
{
id: 3
},
{
id: 4,
images: []
}
];
var filtered = [];
var b = data1.forEach((element, index, array) => {
if(element.images && element.images.length)
filtered.push(element.images[0].name);
});
console.log(filtered);
The output needs to be flat:
['1a', '2a']
How can I make this prettier?
I'm not too familiar with JS map, reduce and filter and I think those would make my code more sensible; the forEach feels unnecessary.
First you can filter out elements without proper images property and then map it to new array:
const filtered = data1
.filter(e => e.images && e.images.length)
.map(e => e.images[0].name)
To do this in one loop you can use reduce function:
const filtered = data1.reduce((r, e) => {
if (e.images && e.images.length) {
r.push(e.images[0].name)
}
return r
}, [])
You can use reduce() to return this result.
var data1 = [{
id: 1,
images: [{
name: '1a'
}, {
name: '1b'
}]
}, {
id: 2,
images: [{
name: '2a'
}, {
name: '2b'
}]
}, {
id: 3
}, {
id: 4,
images: []
}];
var result = data1.reduce(function(r, e) {
if (e.hasOwnProperty('images') && e.images.length) r.push(e.images[0].name);
return r;
}, [])
console.log(result);
All answers are creating NEW arrays before projecting the final result : (filter and map creates a new array each) so basically it's creating twice.
Another approach is only to yield expected values :
Using iterator functions
function* foo(g)
{
for (let i = 0; i < g.length; i++)
{
if (g[i]['images'] && g[i]["images"].length)
yield g[i]['images'][0]["name"];
}
}
var iterator = foo(data1) ;
var result = iterator.next();
while (!result.done)
{
console.log(result.value)
result = iterator.next();
}
This will not create any additional array and only return the expected values !
However if you must return an array , rather than to do something with the actual values , then use other solutions suggested here.
https://jsfiddle.net/remenyLx/7/

Categories

Resources