Using the Lever job posting API, I'm getting JSON results sorted by location, and I'm trying to figure out how to group all those results by "team" within the results, like the Shopify careers page.
Here is the codepen and here is the JSON
I tried adding the following on line 38 of the codepen to try to grab the team values, but it's not outputting as expected (I'm getting one letter per line, which isn't helpful):
for (var x in _data[i].postings[j].categories.team)
I'm sure it's probably something super simple, but I'm definitely not a javascript guy. Any help would be much appreciated!
Assume , the JSON output is
outJSON =
[ {
team: "TeamA",
name: "Ahmed",
field3:"val3"
},
{
team: "TeamB",
name: "Ahmed",
field3:"val43"
},
{
team: "TeamA",
name: "Ahmed",
field3:"val55"
},
]
Then see the groupBy function in the DEMO below:
DEMO :
outJSON = [{
team: "TeamA",
name: "Ahmed",
field3: "val3"
}, {
team: "TeamB",
name: "Ahmed",
field3: "val43"
}, {
team: "TeamA",
name: "Ahmed",
field3: "val55"
}]
var groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
var groubedByTeam = groupBy(outJSON, 'team')
console.log(groubedByTeam);
Then , if you want to loop through categories (teams), get all categories in array :
Object.keys(groubedByTeam) // return ["TeamA","TeamB"]
then :
Object.keys(groubedByTeam).forEach(function(category) {
console.log(`Team ${category} has ${groubedByTeam[category].length} members : `);
groubedByTeam[category].forEach(function(memb,i){
console.log(`---->${i+1}. ${memb.name}.`)
})
});
Related
I have this set of data that I'm trying to convert to map:
x = [
{
food: 'Steak',
ingredients: [
{
item1: 'pepper',
},
{
item2: "salt",
},
],
},
{
food: 'Veggies'
},
{
food: 'Fruits'
},
];
This is my current map function, question is how do I iterate on the ingredients?:
<div>
{Object.keys(x).map(key => (
<a key={key}>{x[key].food}</a>
))}
</div>
Something like this?
x = [
{
food: 'Steak',
ingredients: [
{
item1: 'pepper',
},
{
item2: "salt",
},
],
},
{
food: 'Veggies'
},
{
food: 'Fruits'
},
];
const list = x.map(item =>
({[item.food]: item.ingredients ?
item.ingredients.flatMap(i =>
Object.keys(i).map(k =>
i[k])).join(','): 'no ingredients'}))
console.log(list)
Output:
[
{
"Steak": "pepper,salt"
},
{
"Veggies": "no ingredients"
},
{
"Fruits": "no ingredients"
}
]
A better format for the data:
x = [
{
food: 'Steak',
ingredients: [
"pepper", "salt",
],
},
{
food: 'Veggies'
},
{
food: 'Fruits'
},
];
Naming things is 80% of programming. The other 20% is choosing the right font for your IDE.
If you have an array of objects and the key of object holds no semantic meaning, and there is one key in each object, that's a sign that it should be an array.
You could go one step further:
const ingredients = {
Steak: ["pepper", "salt"],
Veggies: []
Fruits: []
};
The name of the data structure makes sense. It is an "ingredients by food" object.
Where you went off is starting with x as the name of the object. x is an unknown. Start by describing everything clearly, and use JetBrains Mono.
If you want to easily iterate over the object using map (like to render a table in React), then you could do:
const ingredients = [
{Steak: ["pepper", "salt"]},
{Veggies: []},
{Fruits: []}
];
or:
const recipes = [
{food: Steak, ingredients: ["pepper", "salt"]},
{food: Veggies, ingredients: []},
{food: Fruits, ingredients: []}
];
(which is close to the reduction I did to your original data)
That one should be called recipes, which I discovered when I wrote this next function and the names didn't make sense if the object were named ingredients.
recipes.forEach(recipe => {
console.log(`HTML Title: %{recipe.food})
console.log(`HTML Subtitle: Ingredients`)
recipe.ingredients.forEach(ingredient =>
console.log(`* ${ingredient}`)
)
})
See, the names in the data structure make sense, and so do the functions to work with it. And the data structure itself is small and comprehensible. Structure is also data.
JetBrains Mono.
You can store all ingredientItem in one array and then apply Map on that array:
let ingredientItem = [];
x.forEach((item) => {
if (item.ingredients) {
item.ingredients.forEach((ingredient) => {
for (name in ingredient) {
ingredientItem.push(ingredient[name])
}
})
}
})
ingredientItem.map((item) => {
})
I am trying to do sort inside the reduce and I thought I have everything correct but still my result is not sorted as desired.
Here is the code snippet I have:
var studentInfo = [
{
studentId: 1,
addresses: [
{street: '123 Main St'},
]
},
{
studentId: 2,
addresses: [
{street: '456 Front St'}
]
},
{
studentId: 3,
addresses: [
{street: '100 MLK St'}
]
}
];
function appendAddress(studentId, newAddress) {
return studentInfo.reduce(function (info, student) {
if (student.studentId === studentId) {
student = {
studentId: student.studentId,
addresses: student.addresses.concat(newAddress).sort(function (address1, address2) {
return address2.street - address1.stree;
})
};
}
info.push(student);
return info;
}, []);
}
var newAddress = {
street: '166 Devil St'
}
console.log('Result: ' + JSON.stringify(appendAddress(2, newAddress)));
I am getting result as
Result: [{"studentId":1,"addresses":[{"street":"123 Main St"}]},{"studentId":2,"addresses":[{"street":"456 Front St"},{"street":"166 Devil St"}]},{"studentId":3,"addresses":[{"street":"100 MLK St"}]}]
instead of
Result: [{"studentId":1,"addresses":[{"street":"123 Main St"}]},{"studentId":2,"addresses":[{"street":"166 Devil St"},{"street":"456 Front St"}]},{"studentId":3,"addresses":[{"street":"100 MLK St"}]}]
Am I missing anything?
As to the sorting issue, if that was the main thing you were wondering about, you do indeed have a typo as the comment above noted, and also, performing subtraction on non-numeric strings won't get you very far. I used .localeCompare in the solution above.
If you wanted to copy the objects as you were appending, that can still be done more simply, but I don't know if that's what you actually want.
var studentInfo = [
{studentId: 1,addresses: [{street: '123 Main St'}]},
{studentId: 2,addresses: [{street: '456 Front St'}]},
{studentId: 3,addresses: [{street: '100 MLK St'}]}
];
console.log(addAddress(2, {street: "1234 56th Ave"}));
function addAddress(studentId, address) {
const idx = studentInfo.findIndex(o => o.studentId === studentId);
if (idx !== -1) {
return [...studentInfo.slice(0, idx), {
studentId,
addresses: [...studentInfo[idx].addresses, address].sort((a,b) => a.street.localeCompare(b.street))
}, ...studentInfo.slice(idx+1)];
} else {
return [...studentInfo, {studentId, addresses:[address]}];
}
}
But now you're having two different copies of the data with some shared objects.
I have an array of objects and the definition for an object looks something like this:
export class AccountInfo {
accountUid: string;
userType: string;
firstName: string;
middleName: string;
lastName: string;
}
NOTE: The reason I don't have userType as an enum is because the object is populated by a database call and I couldn't figure out a clean way to have the string returned from the db populate the enum.
I want to sort the array so that objects with a userType of 'STAFF' appear first, followed by 'TEACHER', then 'PARENT', then 'STUDENT'.
You can store the order in an array, then just use indexOf with sort to achieve your goal. See the code example below:
const humans = [{
accountUid: "1",
userType: "TEACHER",
}, {
accountUid: "2",
userType: "STAFF",
}, {
accountUid: "3",
userType: "STUDENT",
}, {
accountUid: "4",
userType: "PARENT",
}];
const order = ['STAFF', 'TEACHER', 'PARENT', 'STUDENT'];
const result = humans.sort((a, b) => order.indexOf(a.userType) - order.indexOf(b.userType));
console.log(result)
If you can't use ES6, just use:
humans.sort(function(a, b){
return order.indexOf(a.userType) - order.indexOf(b.userType);
});
Here is another way to do it, probably have an order object to store the orders
const actionOrder = {
"EAT" : 1,
"SLEEP" : 2,
"PLAY" : 3,
} as const;
const users = [{
name: "Mike",
action: "PLAY"
}, {
name: "John",
action: "EAT"
}, {
name: "Harry",
action: "SLEEP"
}
];
users.sort((a,b) => {
return actionOrder[a.action] - actionOrder[b.action];
});
console.log(users);
Im trying to merge 2 data sources in 1, I wanna loop through them and if a specefic value matches than add it to the first object with the same value and add the in the emty array what is already there. No matter how much objects I have.
So lets say I have this information
Source 1
one = {
"teams": [
{
name: 'ABC',
members: [],
rooms: '0'
},
{
name: 'DEF',
members: [],
rooms: '1'
}
]
}
Source 2
two = {
"persons": [
{
name: 'Foo',
gender: 'male',
room: '1'
},
{
name: 'Bar',
gender: 'female',
room: '2'
}
]
}
And what I want is that the 'persons' array merge to the members array if the 'room and rooms' value matches.
What I would assume is something similar like this:
for(var i = 0 ; i < two.persons.length; i++) {
if (one.teams[i].rooms == two.persons[i].room) {
data.teams[i].members.push(two.persons[i]);
}
}
using higher order methods you can do:
one = {
"teams": [
{
name: 'ABC',
members: [],
rooms: '0'
},
{
name: 'DEF',
members: [],
rooms: '1'
}
]
};
two = {
"persons": [
{
name: 'Foo',
gender: 'male',
room: '1'
},
{
name: 'Bar',
gender: 'female',
room: '2'
}
]
};
var ttt = one.teams.map(function(x){
var roomVal= x.rooms;
x.members = two.persons.filter(function(t){
return t.room == roomVal});
return x;
})
one.teams = ttt;
console.log(one)
The problem with your code is that once you iterate the two array, then you do not go back and see if the previous element matched with the current one.
For example, if [0] on each arrays does not match and you iterate to index [1] in the for-loop, you do not have a way to check if two[1] matched one[0].
To do a complete search, you could directly iterate the arrays for each value of two:
two.persons.forEach(function(person) {
one.teams.forEach(function(team) {
if (team.rooms == person.room) {
team.members.push(person);
}
});
});
There are many strategies to do this. But most important you should iterate each array separately. I would use an Array.forEach();
one.teams.forEach(function (team, teamsIndex, teamsArray) {
two.persons.forEach(function (person, personsIndex, personsArray) {
if (team.room == person.room) {
// Do what you need to do.
}
});
});
Didn't check syntax so be aware to read Array.forEach(); documentation.
I have a tree in javascript which has multiple root elements and nested children.
Here's the object:
[{
_id: '546d30905d7edd1d5169181d',
name: 'first'
children: []
}, {
_id: '546d30905d7edd1d2169181d',
name: 'second'
children: []
}, {
_id: '446d30905d7edd1d5169181d',
name: 'third',
children: [{
_id: '446d30905d7e2d1d5169181d',
name: '3child',
children: []
}, {
_id: '446d30915d7e2d1d5169181d',
name: '3child2',
children: [{
_id: '546d30905d7edd1d2569181d',
name: 'second2',
children: []
}]
}]
}, {
_id: '546d30995d7edd1d5169181d',
name: 'fourth',
children: []
}]
This is a truncated document that's being stored in MongoDB using materialized path. The issue is that I need to add a 'sorting' ability, so nodes in the same root can be sorted.
I want to iterate this tree and apply a sort_value such as node['sort_value'] = 0, etc.
Each level will have it's own sort order, starting at 0.
I can simply iterate the tree recursively:
function iterate(items) {
_.each(items, function(page, key) {
if (items.children.length > 0) {
iterate(items.children);
}
});
}
However, I can't figure out how to keep track of the sort orders and also update the object's to include the sort_value field.
Any help would be greatly appreciated! Thank you
I did it so that I used array key for sorting and "synchronized" it with object property (because I needed it saved to DB and restored after) and it works as a charm :)
So something like this, pseudo:
var unsorted = [
0:{"sort_key": "0", "data":"dataaa 0"},
1:{"sort_key": "1", "data":"dataaa 1"},
...
n:{"sort_key": "n", "data":"dataaa n"}
];
function_sort(unsorted){
...
return sorted = [
0:{"sort_key": "n", "data":"dataaa y"},
1:{"sort_key": "44", "data":"dataaa x"},
...
n:{"sort_key": "0", "data":"dataaa z"}
];
}
save = function_save(sorted){
...update sort_key as array key...
return for_saving;
}