I am comparing two arrays and then grouping them into inserts and updates. The updates array should end up including elements that match on id == Id, but where open_balance !- DocumentAmount. The inserts array should include only elements where the id != Id. Notice I am running both through the toString() method because in my scenario one is of type String whereas the other is of type Integer from two different SQL Databases.
Now, with the code I have now, the first grouping works - via the findRecordsToUpdate() function, I get all of the elements matched correctly for the updates - which should be two elements, because these two match on id, but not on the amount:
recordsToUpdate: [
{ Id: '333', DocumentAmount: 20 },
{ Id: '444', DocumentAmount: 10 }
]
But the inserts, which is produced by the findRecordsToInsert() function, are not correct. According to my data I should end up with one element, with an Id of '555' in my recordsToUpdate array, because it's the only element with an Id not found in the other array -- i.e. it's a new record to insert. But instead I end up with 13 elements with my current code?
What am I missing here and what do I need to change to get the correct inserts populated to my recordsToInsert array?:
const sourceArr = [
{ id: 111, open_balance: 10 },
{ id: 222, open_balance: 20 },
{ id: 333, open_balance: 10 },
{ id: 444, open_balance: 20 },
]
const targetArr = [
{ Id: '111', DocumentAmount: 10 },
{ Id: '222', DocumentAmount: 20 },
{ Id: '333', DocumentAmount: 20 },
{ Id: '444', DocumentAmount: 10 },
{ Id: '555', DocumentAmount: 10 },
]
function findRecordsToUpdate () {
if (sourceArr.length && targetArr.length) {
let recordsToUpdate = [];
for (let t of targetArr) {
for (let s of sourceArr) {
if ((t.Id.toString() == s.id.toString()) && (t.DocumentAmount != s.open_balance)) {
recordsToUpdate.push(t);
}
}
}
console.log('recordsToUpdate: ', recordsToUpdate);
return recordsToUpdate;
}
};
function findRecordsToInsert () {
if (sourceArr.length && targetArr.length) {
let recordsToInsert = [];
for (let t of targetArr) {
for (let s of sourceArr) {
if (t.Id.toString() != s.id.toString()) {
recordsToInsert.push(t);
}
}
}
console.log('recordsToInsert: ', recordsToInsert);
return recordsToInsert;
}
};
findRecordsToUpdate();
findRecordsToInsert();
By the way, to clarify, my findRecordsToInsert() function should return a recordsToInsert array like this when done, as the record with an Id of 555 is the only record from the second array that doesn't exist in the first array:
recordsToInsert: [{ Id: '555', DocumentAmount: 10 }]
So, to be clear, it's just the findRecordsToInsert() function that is not working correctly at present.
Use a combination of Array#filter and Array#find to get your insert and update arrays out of targetArr.
'use strict';
const sourceArr = [
{ id: 111, open_balance: 10 },
{ id: 222, open_balance: 20 },
{ id: 333, open_balance: 10 },
{ id: 444, open_balance: 20 },
];
const targetArr = [
{ Id: '111', DocumentAmount: 10 },
{ Id: '222', DocumentAmount: 20 },
{ Id: '333', DocumentAmount: 20 },
{ Id: '444', DocumentAmount: 10 },
{ Id: '555', DocumentAmount: 10 },
];
// Target records with a matching source (on ID) where the amount has changed.
// Update these.
const recordsToUpdate = targetArr
.filter(tar => sourceArr
.find(source => source.id === Number(tar.Id) && source.open_balance !== tar.DocumentAmount));
console.log(recordsToUpdate);
// Target records that have no matching source record (i.e. new records).
// Insert these.
const recordsToInsert = targetArr
.filter(tar => !sourceArr
.find(source => source.id === Number(tar.Id)));
console.log(recordsToInsert);
Edit
Just for the record, in your original code the search in findRecordsToInsert is incorrect. To fix the issue, try to find each target in source and, if not found, add target to the insert array. But it's just a long-winded version of filter-find.
const sourceArr = [
{ id: 111, open_balance: 10 },
{ id: 222, open_balance: 20 },
{ id: 333, open_balance: 10 },
{ id: 444, open_balance: 20 },
]
const targetArr = [
{ Id: '111', DocumentAmount: 10 },
{ Id: '222', DocumentAmount: 20 },
{ Id: '333', DocumentAmount: 20 },
{ Id: '444', DocumentAmount: 10 },
{ Id: '555', DocumentAmount: 10 },
]
function findRecordsToInsert () {
if (sourceArr.length && targetArr.length) {
const recordsToInsert = [];
for (const t of targetArr) {
let found = false;
for (let i = 0; i < sourceArr.length && !found; ++i) {
if (t.Id.toString() === sourceArr[i].id.toString())
found = true;
}
if (!found)
recordsToInsert.push(t);
}
console.log('recordsToInsert: ', recordsToInsert);
return recordsToInsert;
}
};
findRecordsToInsert();
You could take a hash table and just filter the target array.
const
sourceArr = [{ id: 111, open_balance: 10 }, { id: 222, open_balance: 20 }, { id: 333, open_balance: 10 }, { id: 444, open_balance: 20 }],
targetArr = [{ Id: '111', DocumentAmount: 10 }, { Id: '222', DocumentAmount: 20 }, { Id: '333', DocumentAmount: 20 }, { Id: '444', DocumentAmount: 10 }, { Id: '555', DocumentAmount: 10 }],
source = sourceArr.reduce((r, { id, open_balance }) => (r[id] = open_balance, r), {}),
recordsToUpdate = targetArr.filter(({ Id, DocumentAmount }) =>
Id in source && source[Id] !== DocumentAmount),
recordsToInsert = targetArr.filter(({ Id }) => !(Id in source));
console.log(recordsToUpdate);
console.log(recordsToInsert);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
I thought I understood how to loop through a dictionary, but my loop is wrong. I try to access the name of each sub item but my code does not work.
Here is what I did:
list = [
{
title: 'Groceries',
items: [
{
id: 4,
title: 'Food',
cost: 540 ,
},
{
id: 5,
title: 'Hygiene',
cost: 235,
},
{
id: 6,
title: 'Other',
cost: 20,
},
],
}];
function calculateCost(){
let total = 0;
Object.keys(list).forEach((k) => { for (i in k.items) { total += i.data; } });
console.log(total);
return total;
}
Your list is an array includes 1 object and this object has two properties title and items the items here is an array of objects each one of these objects has property cost so to calculate the total cost you need to loop through items array, here is how you do it:
let list = [
{
title: 'Groceries',
items: [
{
id: 4,
title: 'Food',
cost: 540 ,
},
{
id: 5,
title: 'Hygiene',
cost: 235,
},
{
id: 6,
title: 'Other',
cost: 20,
},
],
}];
function calculateCost(){
let total = 0;
list[0].items.forEach(el => {
total += el.cost;
})
console.log(total)
return total;
}
calculateCost();
Your list is an Array, not an Object.
Instead of Object.keys() use Array.prototype.reduce:
const calculateCost = (arr) => arr.reduce((tot, ob) =>
ob.items.reduce((sum, item) => sum + item.cost, tot), 0);
const list = [
{
title: 'Groceries',
items: [
{id: 4, title: 'Food', cost: 10},
{id: 5, title: 'Hygiene', cost: 20},
{id: 6, title: 'Other', cost: 30}
]
}, {
title: 'Other',
items: [
{id: 8, title: 'Scuba gear', cost: 39}
],
}
];
console.log(calculateCost(list)); // 99
Expanding on #Roko's and #mmh4all's answers, the following code adds several verification statements to handle cases where a deeply nested property in your data is not what you expect it to be.
const calculateCost = (orders) => {
let listOfCosts = [];
// For each 'order' object in the 'orders' array,
// add the value of the 'cost' property of each item
// in the order to 'listOfCosts' array.
orders.forEach(order => {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
if (!Array.isArray(order.items)) { return; }
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/parseFloat
const orderCostArr = order.items.map(item =>
isNaN(item.cost) ? 0 : parseFloat(item.cost, 10));
if (orderCostArr.length === 0) { return; }
// Concatenate 'orderCostArr' to the 'listOfCosts' array
//listOfCosts = listOfCosts.concat(orderCostArry);
// Alternate approach is to use the spread syntax (...) to
// push the items in the array returned by 'order.items.map()'
// into the 'listOfCosts' array.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
listOfCosts.push(...orderCostArr);
});
// Use the 'reduce' method on the 'listOfCosts' array
// to get the total cost.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
const totalCost = listOfCosts.reduce(
(accumulator, currentValue) => accumulator + currentValue, 0);
return totalCost;
};
const list = [
{
title: 'Groceries',
items: [
{ id: 4, title: 'Food', cost: 10 },
{ id: 3, title: 'Baked goods', cost: 20 },
{ id: 5, title: 'Hygiene', cost: 0 },
{ id: 6, title: 'Other' }
]
}, {
title: 'Gear',
items: {},
}, {
title: 'Accessories',
items: [],
}, {
title: 'Bags',
}, {
title: 'Other',
items: [
{ id: 10, title: 'Scuba gear', cost: "5" },
{ id: 8, title: 'Scuba gear', cost: "err" },
{ id: 9, title: 'Scuba gear', cost: 59 }
],
}
];
console.log(calculateCost(list)); // 94
So I have an array with 45 items, each item has 2 items, local and visitor team.
I need to create a function that creates 9 matchdays with 5 games in each matchday, but the games can't repeat.
I tried doing this:
const getRandomGame = (items, idsToAvoid) => {
const game = getRandomFromArray(items);
if (idsToAvoid.includes(game[0].id, game[1].id))
return getRandomGame(items, idsToAvoid);
return game;
};
const getRandomFromArray = (items) => {
return items[Math.floor(Math.random() * items.length)];
};
// this is inside another function that tries to generate the matchdays
for (let i = 0; i < 9; i++) {
counter++;
let games = [];
let avoidIds = [];
for (let j = 0; j < 5; j++) {
const game = getRandomGame(copyFinalGames, avoidIds);
const localRng = Math.random() < 0.5;
const local = localRng ? game[0] : game[1];
const visitor = localRng ? game[1] : game[0];
avoidIds.push(local.id, visitor.id);
games.push({
id: counter,
local,
visitor,
});
copyFinalGames = copyFinalGames.filter(
(item) => !(item[0].id === game[0].id && item[1].id === game[1].id)
);
}
gamedays.push({
id: i + 1,
games,
});
}
Which doesn't quite work (games are being repeated) + it's not efficient cause it tries to brute force the rule out repeated games. Any ideas?
The original array looks like this:
[{ id: 1 }, { id: 2}],
[{ id: 3 }, { id: 4}],
[{ id: 5 }, { id: 6}] // here only showing three rows, but it has the 45 possible games
OK, here's an attempt:
const matchupList =
[
[{ id: 1 }, { id: 2}],
[{ id: 3 }, { id: 4}],
[{ id: 5 }, { id: 6}],
[{ id: 6 }, { id: 5}],
[{ id: 3 }, { id: 9}],
[{ id: 8 }, { id: 2}],
[{ id: 4 }, { id: 1}],
[{ id: 2 }, { id: 6}],
[{ id: 7 }, { id: 8}],
[{ id: 5 }, { id: 3}],
[{ id: 3 }, { id: 1}],
[{ id: 2 }, { id: 7}],
[{ id: 7 }, { id: 1}],
[{ id: 4 }, { id: 6}],
[{ id: 7 }, { id: 2}],
[{ id: 8 }, { id: 1}],
[{ id: 9 }, { id: 3}],
[{ id: 5 }, { id: 4}],
[{ id: 5 }, { id: 0}],
[{ id: 0 }, { id: 3}],
[{ id: 1 }, { id: 0}],
[{ id: 0 }, { id: 8}],
[{ id: 9 }, { id: 8}]
];
const pickMatch = (list) => list[Math.floor(Math.random() * list.length)];
const pickMatchDay = (matchupList, matchDaySize) =>
{
let matchChosen;
let teamSeen;
let workingList;
do
{
matchChosen = [];
teamSeen = [];
// Create a copy of the original matchup list so we can remove matches we've already tried
workingList = matchupList.concat();
while(matchChosen.length < matchDaySize && workingList.length)
{
let local, visitor;
let teamPairing = pickMatch(workingList);
let fromId = matchupList.indexOf(teamPairing);
teamPairing = teamPairing.map(i => i.id);
// If this pairing has NO teams we've already seen...
if(teamPairing.findIndex(i => teamSeen.includes(i)) === -1)
{
// Randomly decide who is local/visitor
if(Math.random() < 0.5)
[local, visitor] = teamPairing;
else
[visitor, local] = teamPairing;
matchChosen.push(
{
id: matchChosen.length + 1,
local,
visitor,
fromId
});
// Push this pairing's teams to the list of teams we've seen
teamSeen.push(...teamPairing);
}
// Remove this matchup from the possible matchups we can choose
workingList.splice(workingList.indexOf(teamPairing), 1);
}
// Due to the limited number of pairings available (and that pairings are variable),
// it's quite possible we'll reach this point with only 3 or 4 matches chosen,
// but having exhausted all available matchups.
// If this happens, we start over.
// Not really necessary if you can guarantee 45 matchups and 5 matches per day
} while(matchChosen.length < matchDaySize);
return(matchChosen);
};
const gamedays = [];
for(let index = 0; index < 5; index++)
gamedays.push({id: index + 1, games: pickMatchDay(matchupList, 5)});
console.log(gamedays);
Some notes:
Pairings can still be repeated across different days. You might find that team 1 plays team 2 on both day 1 and day 3, for instance.
pickMatchDay has a real possibility of infinitely looping, e.g. you can ask for 6 games, which is just impossible with only 10 teams.
I have been trying to create a summary of an array of objects where it's grouped by the value of one property and 2 or more properties should get summed.
But for some reason the way I am trying is only giving me 2 values the property I am grouping by and first property I am summing.
I am unable to sum the next property.
The array I am starting with
combinedItems
[
{
itemSi: 1,
productId: 'one',
taxableValue: 100,
taxValue: 10,
product: { id: 'one', productName: 'product one', taxId: 'one' },
tax: { id: 'one', taxName: 'tax one' }
},
{
itemSi: 2,
productId: 'two',
taxableValue: 100,
taxValue: 10,
product: { id: 'two', productName: 'product two', taxId: 'one' },
tax: { id: 'one', taxName: 'tax one' }
}
]
I need to be able to group by the taxName and sum the taxableValue and taxValue.
const summaryValues = new Map<any []>();
for(const {tax, taxableValue, taxValue} of combinedItems)
summaryValues.set(
tax.taxName,
(summaryValues.get(tax.taxName) || 0) + taxableValue,
(summaryValues.get(tax.taxName) || 0) + taxValue,
);
const summaries = [...summaryValues]
console.log(summaries);
const taxSummary = summaries.map(x => ({
taxName: x[0],
taxableValue: x[1],
taxValue: x[2]
}));
console.log(taxSummary)
The result I am getting
[ [ 'tax one', 200 ] ]
[ { taxName: 'tax one', taxableValue: 200, taxValue: undefined } ]
This is how the combined items are gotten:
const items: any[] = [
{
itemSi: 1,
productId: "one",
taxableValue: 100,
taxValue: 10
},
{
itemSi: 2,
productId: "two",
taxableValue: 100,
taxValue: 10
}
];
const products: any[] = [
{
id: "one",
productName:"product one",
taxId: "one"
},
{
id: "two",
productName:"product two",
taxId: "one"
}
]
const taxes: any[] = [
{
id: "one",
taxName:"tax one"
},
{
id: "two",
taxName:"tax two"
}
]
let combinedItems: any [] = []
combinedItems = items.map(x => {
let pdtItem = products.find(z => z.id === x.productId);
let taxItem = taxes.find(z => z.id === pdtItem.taxId);
let item = {...x, product: {...pdtItem }, tax: {...taxItem}};
return item;
});
console.log(combinedItems)
Map is a key-value store. What you're trying to do appears to be calling set with three arguments, whereas it only takes two (key and value).
If you need to produce multiple aggregations, you could store the results in an object:
const summaries = new Map();
for (const { tax: { taxName }, taxableValue, taxValue } of combinedItems) {
const currentSummary = summaries.get(taxName) || { taxableValue: 0, taxValue: 0 }
summaries.set(
taxName,
{ taxableValue: currentSummary.taxableValue + taxableValue, taxValue: currentSummary.taxValue + taxValue }
);
}
So I'm working on a problem that I've been staring at for far too long. I have an array of people, each represented by an object. Inside each person object is a value for friends, which is an array.
The friends array contains an object for each friend, with one of the key/value pairs being name: 'name'.
I need to find how many friends of a given person have names that start with given letter.
Below is the array of people, including the friends array for each person. After that is the code I've worked with out so far, trying to use reduce.
var customers = [{
name: "Courtney",
age: 43,
balance: "$3,400",
friends: [{
id: 0,
name: "Justice Lara"
}, {
id: 1,
name: "Duke Patrick"
}, {
id: 2,
name: "Herring Hull"
}, {
id: 3,
name: "Johnnie Berg"
}]
}, {
name: "Regina",
age: 53,
balance: "$4,000",
friends: [{
id: 0,
name: "Cheryl Kent"
}, {
id: 1,
name: "Greta Wells"
}, {
id: 2,
name: "Gutierrez Waters"
}, {
id: 3,
name: "Cooley Jimenez"
}]
}, {
name: "Jay",
age: 28,
balance: "$3,000",
friends: [{
id: 0,
name: "Cross Barnett"
}, {
id: 1,
name: "Raquel Haney"
}, {
id: 2,
name: "Cassandra Martin"
}, {
id: 3,
name: "Shelly Walton"
}]
}];
var friendFirstLetterCount = function(array, customer, letter) {
let friendNames = [];
for (let i = 0; i < customer.friends.length; i++) {
friendNames.push(customer.friends[i].name);
}
let friendCount = _.filter(friendNames, function(current, index, array) {
return current.toLowerCase().charAt(0) === letter.toLowerCase();
});
return friendCount.length;
};
This seems to work. Read the inline comments for an explanation of how:
function friendFirstLetterCount(array, customer, letter) {
// Find the customer object in the array, where the customer name is equal to customer.
const customerObj = array.filter(arrayCustomer => arrayCustomer.name === customer)[0];
// Return zero if customer not found.
// (Up to you how you handle this, you might want an exception instead).
if (!customerObj) return 0;
// Find all customer friends whose name starts with letter and return the length.
return customerObj.friends.filter(friend => friend.name.startsWith(letter)).length;
}
Test run
friendFirstLetterCount(customers, "Regina", "C");
Result
2
There are likely a few edge cases you want to watch out for; for example, what happens if the customer isn't found (see comments), and what happens if the customer doesn't have any friends.
Edit: I also think it's more readable with the following parameter and variable names
function friendFirstLetterCount(array, name, letter) {
// Find the customer object in the array, where the customer name is equal to customer.
const customer = array.filter(customer => customer.name === name)[0];
// Return zero if customer not found.
if (!customer) return 0;
// Find all customer friends whose name starts with letter and return the length.
return customer.friends.filter(friend => friend.name.startsWith(letter)).length;
}
i didn't achieve it exaclty but i think this could be a really clean solution :
var matches = [];
customers.forEach((cus) => {
matches[cus.name] = cus.friends.filter(function(friend)
{
let friends = friend.name.startsWith('C');
return friends;
})
});
like this
`
0:[]
1:[]
2:[{...}]
0:(2) {id: 3, name: "Shelly Walton"}`
it returns you a list of the matching friends for each customer, you can tweak it to get something like 'customerName': []
edited with the cus.name and .length :
var matches = [];
customers.forEach((cus) => {
matches[cus.name] = cus.friends.filter(function(friend)
{
let friends = friend.name.startsWith('C');
return friends;
}).length
});
you will get [ Courtney: 0, Regina: 2, Jay: 2 ] as a result
var customers = [{
name: "Courtney",
age: 43,
balance: "$3,400",
friends: [{
id: 0,
name: "Justice Lara"
}, {
id: 1,
name: "Duke Patrick"
}, {
id: 2,
name: "Herring Hull"
}, {
id: 3,
name: "Johnnie Berg"
}]
},
{
name: "Regina",
age: 53,
balance: "$4,000",
friends: [{
id: 0,
name: "Cheryl Kent"
}, {
id: 1,
name: "Greta Wells"
}, {
id: 2,
name: "Gutierrez Waters"
}, {
id: 3,
name: "Cooley Jimenez"
}]
},
{
name: "Jay",
age: 28,
balance: "$3,000",
friends: [{
id: 0,
name: "Cross Barnett"
}, {
id: 1,
name: "Raquel Haney"
}, {
id: 2,
name: "Cassandra Martin"
}, {
id: 3,
name: "Shelly Walton"
}]
}
]
var friendFirstLetterCount = function(array, customerName, letter) {
const customerObj = array.find(customer => customer.name.toLowerCase() === customerName.toLowerCase());
let friendNames = customerObj.friends;
let friendCount = friendNames.filter(friend => friend.name.toLowerCase().startsWith(letter.toLowerCase()));
return friendCount.length;
};
const count = friendFirstLetterCount(customers, 'Regina', 'c');
console.log(count)
Doing it very functionally, here are two functions that do logical chunks of the work...
// get the first letter of every name in an object's fiends array
const friendsInitials = object => object.friends.map(el => el.name[0]);
// count the number of times a letter appears in an array of letters
const count = (array, letter) => array.filter(el => el === letter).length;
With those, we can write a function that does what we want for an input object...
// count the number of times letter is the first letter of the friends' names
const initialCount = (object, letter) => count(friendsInitials(object), letter);
And run it like this...
// get an array of counts by mapping the initialCount over the input
const customers = [ /* OP customers array */ ];
const letter = "C";
const firstInitialCounts = customers.map(c => initialCount(c, letter));
Demo...
// get the first letter of every name in an object's fiends array
const friendsInitials = object => object.friends.map(el => el.name[0]);
// count the number of times letter appears in an array of letters
const count = (array, letter) => array.filter(el => el === letter).length;
// count the number of times letter is the first letter of the friends' names
const initialCount = (object, letter) => count(friendsInitials(object), letter);
// get an array of counts by mapping the initialCount over the input
const customers = [{
name: "Courtney",
age: 43,
balance: "$3,400",
friends: [{
id: 0,
name: "Justice Lara"
}, {
id: 1,
name: "Duke Patrick"
}, {
id: 2,
name: "Herring Hull"
}, {
id: 3,
name: "Johnnie Berg"
}]
}, {
name: "Regina",
age: 53,
balance: "$4,000",
friends: [{
id: 0,
name: "Cheryl Kent"
}, {
id: 1,
name: "Greta Wells"
}, {
id: 2,
name: "Gutierrez Waters"
}, {
id: 3,
name: "Cooley Jimenez"
}]
}, {
name: "Jay",
age: 28,
balance: "$3,000",
friends: [{
id: 0,
name: "Cross Barnett"
}, {
id: 1,
name: "Raquel Haney"
}, {
id: 2,
name: "Cassandra Martin"
}, {
id: 3,
name: "Shelly Walton"
}]
}];
const letter = "C";
const firstInitialCounts = customers.map(c => initialCount(c, letter));
console.log(firstInitialCounts)
3 Parameters
Array of objects - (cutomers)
String - The name of a customer.name (name)
String - The letter that the friend.names must start with (letter).
Steps
.flatMap() customers array.
Compare customer.name with the name parameter
customer.name.toLowerCase().includes(name.toLowerCase())
Once found, .flatMap() on customer.friends array
Compare friend.name with the letter parameter. true returns a 1 otherwise 0 is returned.
if(friend.name.toLowerCase().charAt(0) === letter.toLowerCase()) {
return 1;
} else {
return 0;
}
Next the returned array is .filter(a => a) to remove any "" and then .reduce() to a sum.
const customers =[{name:"Courtney",age:43,balance:"$3,400",friends:[{id:0,name:"Justice Lara"},{id:1,name:"Duke Patrick"},{id:2,name:"Herring Hull"},{id:3,name:"Johnnie Berg"}]},{name:"Regina",age:53,balance:"$4,000",friends:[{id:0,name:"Cheryl Kent"},{id:1,name:"Greta Wells"},{id:2,name:"Gutierrez Waters"},{id:3,name:"Cooley Jimenez"}]},{name:"Jay",age:28,balance:"$3,000",friends:[{id:0,name:"Cross Barnett"},{id:1,name:"Raquel Haney"},{id:2,name:"Cassandra Martin"},{id:3,name:"Shelly Walton"}]}];
function findFriend(array, name, letter) {
const result = array
.flatMap((customer) => {
//console.log(customer.name.toLowerCase());
if (customer.name.toLowerCase().includes(name.toLowerCase())) {
//console.log(customer.friends)
return customer.friends.flatMap((friend) => {
//console.log(friend.name)
if (friend.name.toLowerCase().charAt(0) === letter.toLowerCase()) {
return 1;
} else {
return 0;
}
});
}
})
.filter((a) => a);
//console.log(result)
return result.reduce((sum, add) => sum + add);
}
console.log("Courtney has "+findFriend(customers, "courtney", "j")+" friends whose names starts with a 'J'");
console.log("Regina has "+findFriend(customers, "regina", "g")+" friends whose names starts with a 'G'");
console.log("Jay has "+findFriend(customers, "jay", "c")+" friends whose names starts with a 'C'");
I have been trying to delete an element with an ID in nested array.
I am not sure how to use filter() with nested arrays.
I want to delete the {id: 111,name: "A"} object only.
Here is my code:
var array = [{
id: 1,
list: [{
id: 123,
name: "Dartanan"
}, {
id: 456,
name: "Athos"
}, {
id: 789,
name: "Porthos"
}]
}, {
id: 2,
list: [{
id: 111,
name: "A"
}, {
id: 222,
name: "B"
}]
}]
var temp = array
for (let i = 0; i < array.length; i++) {
for (let j = 0; j < array[i].list.length; j++) {
temp = temp.filter(function(item) {
return item.list[j].id !== 123
})
}
}
array = temp
You can use the function forEach and execute the function filter for every array list.
var array = [{ id: 1, list: [{ id: 123, name: "Dartanan" }, { id: 456, name: "Athos" }, { id: 789, name: "Porthos" }] }, { id: 2, list: [{ id: 111, name: "A" }, { id: 222, name: "B" }] }];
array.forEach(o => (o.list = o.list.filter(l => l.id != 111)));
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
To remain the data immutable, use the function map:
var array = [{ id: 1, list: [{ id: 123, name: "Dartanan" }, { id: 456, name: "Athos" }, { id: 789, name: "Porthos" }] }, { id: 2, list: [{ id: 111, name: "A" }, { id: 222, name: "B" }] }],
result = array.map(o => ({...o, list: o.list.filter(l => l.id != 111)}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could create a new array which contains elements with filtered list property.
const result = array.map(element => (
{
...element,
list: element.list.filter(l => l.id !== 111)
}
));
You can use Object.assign if the runtime you are running this code on does not support spread operator.
Array.filter acts on elements:
var myArray = [{something: 1, list: [1,2,3]}, {something: 2, list: [3,4,5]}]
var filtered = myArray.filter(function(element) {
return element.something === 1;
// true = keep element, false = discard it
})
console.log(filtered); // logs [{something: 1, list: [1,2,3]}]
You can use it like this:
var array = [{
id: 1,
list: [{
id: 123,
name: "Dartanan"
}, {
id: 456,
name: "Athos"
}, {
id: 789,
name: "Porthos"
}]
}, {
id: 2,
list: [{
id: 111,
name: "A"
}, {
id: 222,
name: "B"
}]
}]
for (var i = 0; i < array.length; ++i) {
var element = array[i]
// Filter the list
element.list = element.list.filter(function(listItem) {
return listItem.id !== 111 && listItem.name !== 'A';
})
}
console.log(array)