Joins and Aggregates in Javascript Arrays - javascript

I have been trying for hours to do this using json.js but is just too much for something that seems simple. I have this example data:
var hotels = [
{ id: 101, Name: "Hotel 101", WebFacilities: [8, 9, 10] },
{ id: 102, Name: "Hotel 101", WebFacilities: [8] },
{ id: 103, Name: "Hotel 101", WebFacilities: [8, 10] }
];
var facilities = [
{ id: 8, Name: "Facility 8" },
{ id: 9, Name: "Facility 9" },
{ id: 10, Name: "Facility 10" }
];
I want to get this:
var selectedFacilities = [
{ id: 8, Name: "Facility 8", Count: 3 },
{ id: 9, Name: "Facility 9", Count: 1 },
{ id: 10, Name: "Facility 10", Count: 2 }
];
How do I do this?

So it appears you're trying to count how many of each facility there is.
Here's one way to write the query using C#:
var hotelFacilities =
from hotel in hotels
from id in hotel.WebFacilities
group id by id;
var query =
from facility in facilities
join g in hotelFacilities on facility.id equals g.Key
select new
{
id = facility.id,
Name = facility.Name,
Count = g.Count(),
};
Now if you can picture this using the method syntax, it is almost a 1:1 transformation to the linq.js version.
Note the way the compiler translates the above will usually include the GroupBy() call within the previous SelectMany() call. However written this way will make writing the linq.js equivalent query easier and less awkward.
var hotelFacilities = hotels
.SelectMany(hotel => hotel.WebFacilities)
.GroupBy(id => id);
var query = facilities
.Join(
hotelFacilities,
facility => facility.id,
g => g.Key,
(facility, g) => new
{
id = facility.id,
Name = facility.Name,
Count = g.Count(),
}
);
And the equivalent linq.js query.
var hotelFacilities = Enumerable.From(hotels)
.SelectMany("hotel => hotel.WebFacilities")
.GroupBy("id => id")
.ToArray();
var query = Enumerable.From(facilities)
.Join(
hotelFacilities,
"facility => facility.id",
"g => g.Key()",
"(facility, g) => { id: facility.id, Name: facility.Name, Count: g.Count() }"
).ToArray();

Use this:
var selectedFacilities = facilities;
for(var i = 0; i < facilities.length; i++) {
for(var j = 0; j < hotels.length; j++) {
if(hotels[j]["id"] == facilities[i]["id"]) {
// Add data
selectedFacilities[i]["Count"] = hotels[i]["WebFacilities"].length;
} else {
selectedFacilities[i]["Count"] = 0;
}
}
}

Related

I want to change the structure of my array

I need to modify a data which is coming from API. The data is coming in the form of array of objects.
const crosses = [
{
fatherLineId: 8,
fatherLineName: "2ART18-0008",
id: 54,
motherLineId: 5,
motherLineName: "2ART18-0005",
},
{
fatherLineId: 3
fatherLineName: "2ART18-0003",
id: 55,
motherLineId: 5,
motherLineName: "2ART18-0005",
}
]
I want my data to be restructured in the form of:
const resultantArr = [
{
enteryNumber: 1,
ParentName: "2ART18-0008"
},
{
entryNumber: 2,
ParentName: "2ART18-0005",
},
{
entryNumber: 3,
ParentName: "2ART18-0003"
},
and so on ...
];
Here the parentName property will have motherLineName values and fatherLineName values in the order.
When you get the result of the api call, loop through it and map the data toy our custom object, I can't provide a complete example based on your question but something like this:
You may also need to parse the apiresult into json using JSON.parse()
var resultantArr = [];
for(var i = 0; i < apiresult.length; i++)
{
resultantArr.push({"enteryNumber" : i + 1 , "ParentName" : apiresult[i].fatherLineName });
}
Loop over the array and push two separate objects into an output array. And keep a record of each object entryname that you increment by two at the end of each iteration.
const crosses=[{fatherLineId:8,fatherLineName:"2ART18-0008",id:54,motherLineId:5,motherLineName:"2ART18-0005"},{fatherLineId:3,fatherLineName:"2ART18-0003",id:55,motherLineId:5,motherLineName:"2ART18-0005"}];
const out = [];
let count = 1;
crosses.forEach(obj => {
const { fatherLineName, motherLineName } = obj;
out.push({
entryNumber: count,
parentName: fatherLineName
});
out.push({
entryNumber: count + 1,
parentName: motherLineName
});
count = count + 2;
});
console.log(out);
Hope it helps you... 🙂
const crosses = [
{
fatherLineId: 8,
fatherLineName: "2ART18-0008",
id: 54,
motherLineId: 5,
motherLineName: "2ART18-0005",
},
{
fatherLineId: 3,
fatherLineName: "2ART18-0003",
id: 55,
motherLineId: 5,
motherLineName: "2ART18-0005",
}
];
var result = [];
var count = 1;
crosses.forEach(cross => {
result.push({
parentName: cross.fatherLineName,
entryNumber: count++,
}),
result.push({ parentName: cross.motherLineName,
entryNumber: count++,
})
});
result

Toss players in unique combinations

var players = [
{ id: 1, name : 'player1'},
{ id: 2, name : 'player2'},
{ id: 3, name : 'player3'},
{ id: 4, name : 'player4'},
{ id: 5, name : 'player5'},
{ id: 6, name : 'player6'},
{ id: 7, name : 'player7'},
{ id: 8, name : 'player8'},
{ id: 9, name : 'player9'},
{ id: 10, name : 'player10'},
{ id: 11, name : 'player11'},
{ id: 12, name : 'player12'},
{ id: 13, name : 'player13'},
{ id: 14, name : 'player14'},
{ id: 15, name : 'player15'},
{ id: 16, name : 'player16'}]
I want to toss games with 2 players aginst 2 players.
So one round is 4 games with 2 vs 2.
One player can never be in team with a player it already played with.
I want to build a function that randomize all the games.
so i want something like this but with all the games in the turnament.
Then they play 4 games at the time and then switch players and 4 new games start.
games = [{ team1: [{ id: 1, name : 'player1'},{ id: 2, name : 'player2'}], team2 :[{ id: 3, name : 'player3'},{ id: 4, name : 'player4'}] }]
To get all combinations for a maximal number of possible games rounds (every player plays with each other player exactly once), I used https://math.stackexchange.com/a/3094469 as inspiration.
// From: https://stackoverflow.com/a/12646864/9487478
const shuffleArray = (array) => {
let shuffledArray = [...array];
for (let i = shuffledArray.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]];
}
return shuffledArray;
}
// Note: The number of players needs to be even.
let createGames = (playerArr) => {
let players = [...playerArr];
const teamsPerRound = [],
rounds = mod = players.length - 1,
gamesPerRound = 4,
// Helper for checking how often a player is confronted with another player.
confrontations = Array(players.length).fill().map(x => Array(players.length).fill(0));
// Inspired by: https://math.stackexchange.com/a/3094469
// Create as many unique teams as possible, whereas within a round every player occurs exactly once.
for (let i = 0; i < rounds; i++) {
let team = [[
players.length - 1,
(players.length + i) % mod
]];
for (let k = 1; k < (players.length / 2); k++) {
team.push([
(players.length + i + k) % mod,
(players.length + i - k) % mod
]);
}
teamsPerRound.push(team);
console.log(`Teams-Round ${i+1}`, JSON.stringify(team));
}
// Now that we have teams, we can create the games. Let's shuffle the teams per round before to ensure it's more random.
const games = shuffleArray(teamsPerRound).map(teams => {
let roundMatches = [];
teams = shuffleArray(teams);
for (let i = 0; i < teams.length/2; i++) {
let first = teams[i], second = teams[teams.length - 1 - i];
roundMatches.push({
team1: first.map(x => ({...players[x]})),
team2: second.map(x => ({...players[x]}))
})
// Helper for checking how often a player is confronted with another player.
first.forEach(x => second.forEach(y => (confrontations[x][y]++, confrontations[y][x]++)));
}
return roundMatches;
});
confrontations.forEach((x,i) => console.log(`Confrontations (playerIndex: ${i})`, JSON.stringify(x), x.reduce((acc, val) => acc += val)));
return games;
}
var players = [
{ id: 1, name : 'player1'},
{ id: 2, name : 'player2'},
{ id: 3, name : 'player3'},
{ id: 4, name : 'player4'},
{ id: 5, name : 'player5'},
{ id: 6, name : 'player6'},
{ id: 7, name : 'player7'},
{ id: 8, name : 'player8'},
{ id: 9, name : 'player9'},
{ id: 10, name : 'player10'},
{ id: 11, name : 'player11'},
{ id: 12, name : 'player12'},
{ id: 13, name : 'player13'},
{ id: 14, name : 'player14'},
{ id: 15, name : 'player15'},
{ id: 16, name : 'player16'}
];
const games = createGames(players);
console.log("Matches", games);

Add new key value pair to object - REACT NATIVE

I wanted to ask if someone can help do the following.
How do I add a new key value pair to an existing object that I have inside an array fetched from an API.
Basically, after fetching from API I have an array name utils which has the response.
// utils = [
{
id: 1,
item: 10,
name: "candybar"
},
{
id: 2,
item: 12,
name: "whitechocolatebar"
}
]
now I have written some conditional statements for whenever like the following:
for (i in utils){
if(utils[i].name == "candybar"){
utils.push({ new_name : "Candy Bar" });
}else if(utils[i].name == "whitechocolatebar"){
utils.push({ new_name : "White Chocolate Bar" });
}else{
utils.push(utils[i].name);
}
}
now this gives me :
utils = [
{
id: 1,
item: 10,
name: "candybar"
},
{
id: 2,
item: 12,
name: "whitechocolatebar"
},
{
new_name: "Candy Bar"
},
{
new_name: "White Chocolate Bar"
}
]
But i want to have the array utils in the following manner:
utils = [
{
id: 1,
item: 10,
name: "candybar" ,
new_name: "Candy Bar"
},
{
id: 2,
item: 12,
name: "whitechocolatebar",
new_name: "White Chocolate Bar"
}]
Can someone help me achieve this?
Kind Regards and Thank you.
you can do it like this
utils = utils.map(item => {
let new_name = item.name;
if(item.name === 'candybar'){
new_name = 'Candy Bar';
} else if (item.name === 'whitechocolatebar'){
new_name = 'White Chocolate Bar';
}
return ({ ...item, new_name });
});

How to best call a simple filter function

I'm trying to improve the way I write javascript and am looking for a better way that calls a helper function and passes in a variable into that function rather than writing the actual filter function. To explain better, this works:
courses = courses.filter(course => course.id == 3);
But I'd rather just be able to put something like:
courses.filterId(3);
And put the helper function at the bottom.
So in other words, fixing the code inbetween the /* ERROR INBETWEEN HERE */ comments may be the best way of asking for help.
Why is the error logging this message? courses.filterId is not a function
Thanks for any help here.
let tutors = [
{
name: "Bob",
age: 29,
id: 1
},
{
name: "Charlie",
age: 24,
id: 2
},
{
name: "Elanor",
age: 54,
id: 3
},
{
name: "Michael",
age: 66,
id: 4
}
],
courses = [
{
code: "AA01",
description: "Javascript IIFEs, maps, filters, reduces, etc",
id: 3
},
{
code: "AO83",
description: "Arrays, for of loops, etc",
id: 1
},
{
code: "AX40",
description: "CSS, HTML",
id: 3
},
{
code: "BX92",
description: "SQL, Node",
id: 2
},
{
code: "CC24",
description: "PHP, Java",
id: 1
},
{
code: "DI30",
description: "MongoDB",
id: 4
}
],
theHTML = '<table><tr><th>Code</th><th>Description</th><th>ID</th><th>Name</th></tr>',
container = document.querySelector('#container');
courses.forEach((course) =>
tutors.forEach((tutor) =>
tutor.id == course.id &&
(course["name"] = tutor.name)
)
);
/* USE THIS IF YOU WANNA FILTER */
//courses = courses.filter(course => course.id == 3);
/* ERROR INBETWEEN HERE */
function filterId(getID){
return courses.filter(course => course.id == getID);
}
courses.filterId(3);
/* ERROR INBETWEEN HERE */
courses.forEach(function(course) {
theHTML += '<tr>';
for (let column in course) {
theHTML += '<td>' + course[column] + '</td>';
}
theHTML += '</tr>';
});
theHTML += ('</table>');
container.innerHTML = theHTML;
// without arrow functions
/*
courses.forEach(function(course) {
tutors.forEach(function(tutor) {
if (tutor.id == course.id) {
course["name"] = tutor.name;
}
});
});
*/
<div id='container'></div>
Codepen URL: https://codepen.io/anon/pen/GbMYJW
If you really want a function like that, use Lodash's _.filter:
const filtered = _.filter(courses, ["id", 3]);
let tutors = [
{
name: "Bob",
age: 29,
id: 1
},
{
name: "Charlie",
age: 24,
id: 2
},
{
name: "Elanor",
age: 54,
id: 3
},
{
name: "Michael",
age: 66,
id: 4
}
],
courses = [
{
code: "AA01",
description: "Javascript IIFEs, maps, filters, reduces, etc",
id: 3
},
{
code: "AO83",
description: "Arrays, for of loops, etc",
id: 1
},
{
code: "AX40",
description: "CSS, HTML",
id: 3
},
{
code: "BX92",
description: "SQL, Node",
id: 2
},
{
code: "CC24",
description: "PHP, Java",
id: 1
},
{
code: "DI30",
description: "MongoDB",
id: 4
}
];
const res = _.filter(courses, ["id", 3]);
console.log(res);
.as-console-wrapper { max-height: 100% important; top: auto; }
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.11/lodash.min.js"></script>
You can assign the function reference so that courses.filterId is a function.
courses.filterId = filterId
Then, use it like so:
courses.filterId(3).forEach(...)
Alternatively, you can define the function directly on the courses.filterId property:
courses.filterId = id => courses.filter(course => course.id === id)
let tutors = [
{
name: "Bob",
age: 29,
id: 1
},
{
name: "Charlie",
age: 24,
id: 2
},
{
name: "Elanor",
age: 54,
id: 3
},
{
name: "Michael",
age: 66,
id: 4
}
],
courses = [
{
code: "AA01",
description: "Javascript IIFEs, maps, filters, reduces, etc",
id: 3
},
{
code: "AO83",
description: "Arrays, for of loops, etc",
id: 1
},
{
code: "AX40",
description: "CSS, HTML",
id: 3
},
{
code: "BX92",
description: "SQL, Node",
id: 2
},
{
code: "CC24",
description: "PHP, Java",
id: 1
},
{
code: "DI30",
description: "MongoDB",
id: 4
}
],
theHTML =
"<table><tr><th>Code</th><th>Description</th><th>ID</th><th>Name</th></tr>",
container = document.querySelector("#container");
courses.forEach(course =>
tutors.forEach(
tutor => tutor.id == course.id && (course["name"] = tutor.name)
)
);
function filterId(getID) {
return courses.filter(course => course.id == getID);
}
courses.filterId = filterId;
courses.filterId(3).forEach(function(course) {
theHTML += "<tr>";
for (let column in course) {
theHTML += "<td>" + course[column] + "</td>";
}
theHTML += "</tr>";
});
theHTML += "</table>";
container.innerHTML = theHTML;
<div id='container'></div>
With courses.filterId(3) you are calling a function which is on the Array ( ie. Array.prototype) - and it's not there ! When you have defined the function filterId it is on the default window object. The simplest fix is to pass both the Array AND the ID to the filterId function, so it will look something like...
function filterId(arr,ID) { return arr.filter(course => course.id == ID) }
Hope this helps.
You try to run function filterId as member of courses array, but it doesn't exist in Array prototype.
Option 1 try to use method find link
example
let a = [{id:2, test:2}, {id:3, test:3}]
let item = a.find((item) => item.id === 2)
//result {id: 2, test: 2}
Option 2 just call filterId(getID) it take courses from function scope.

ES6 - How to return a nested object property value by filtering in Java Script

Finding the nested object property value based on filter
Please suggest the best ways of identifying getting name for the given item id 03.
const product = products.find(product => product.items.some(item => item.id === '03'));
Gives the product but will have to loop again to find the name ?
const products = [
{
id: 'p1',
items: [
{
id: 01,
name: 'iphone'
},
{
id: 02,
name: 'samsung'
},
{
id: 03,
name: 'oneplus'
}
]
},
{
id: 'p2',
items: [
{
id: 04,
name: 'nokia'
},
{
id: 05,
name: 'nexus'
},
{
id: 06,
name: 'phone3'
}
]
}
]
}
]
Since you seem to be concerned about performance, and it looks like there will only be one matching id - the classic for loop is best suited for this task.
let matchingItem;
for (let i = 0; i < products.length; i++){
const product = products[i];
matchingItem = product.items.find(item => item.id === "03");
if (matchingItem) {
break;
}
}
It's not very fancy, but the ability to stop execution as soon as a match is found makes it the best choice.
I'd do like:
const product = products
.reduce((acc, product) => {
return [...acc, ...product.items];
}, [])
.find(item => item.id === "03");
const productName = product && product.name;
console.log(productName); // oneplus

Categories