looping over objects javascript - javascript

So recently I learned about using for in loops to loop over objects. We were given this problem to solve regarding a basic cart object that contains name of object and then quantity and price.
const cart = {
"Gold Round Sunglasses": { quantity: 1, priceInCents: 1000 },
"Pink Bucket Hat": { quantity: 2, priceInCents: 1260 },
};
We have to write 2 functions, one that calculates total cost of inventory in cents and the other displays the inventory.
The calculateCartTotal function will take in the cart and return a total price, in cents, of everything inside of it.
The printCartInventory function will take in the cart and return a string, joined by \n, of the quantity and name of each item.
I was able to the finish question one with ease but am struggling with the 2nd one.
1st function:
function calculateCartTotal(cart) {
let total = 0;
for(let item in cart){
const product = cart[item]
const quantity = product.quantity
const price = product.priceInCents
total += quantity * price
}
return total
}
2nd function:
function printCartInventory(cart) {
let inventory = ""
for(let item in cart){
const product = cart[item]
const quantity = product.quantity
inventory += `${quantity}x${product}/n`
}
return inventory
}
When I test the 2nd function the autograder gives this error:
expected '2x[object Object]/n1x[object Object]/n1x[object Object]/n3x[object Object]/n' to include '2xCanvas Tote Bag\n1xBlack and White Chuck On Dress\n1xNatural Straw Wide Brim Hat\n3xBlue Stripe Casual Shirt'

When you look at the error message, note the part that says [object Object]. This is part of your code's output, and should ring a bell. It means your code tries to put an object in a string, instead of a string.
The guilty code is here:
inventory += `${quantity}x${product}/n`
product is not a string, but an object. It is not what you intended to output there. What you want to output is the name of the product, which is the key, not the value associated with that key. So it should be:
inventory += `${quantity}x${item}/n`

Related

How to get all elements even if they have the same data

I have a project where I would like to gather in all brandname and price from a site.
for that reason I have the following code:
List<WebElement> list_of_products = driver.findElements(By.xpath(loc.getProperty("brandName")));
List<WebElement> list_of_products_price = driver.findElements(By.xpath(loc.getProperty("finalPrice")));
//System.out.println("ezek a termékek"+ list_of_products);
// Use of HashMaop to store Products and Their prices(after conversion to
// Integer)
String product_name;
String product_price;
int int_product_price;
HashMap<Integer, String> map_final_products = new HashMap<>();
{
for (int i = 0; i < list_of_products.size(); i++) {
product_name = list_of_products.get(i).getText();// Iterate and fetch product name
product_price = list_of_products_price.get(i).getText();// Iterate and fetch product price
product_price = product_price.replaceAll("[^0-9]", "");// Replace anything will space other than numbers
int_product_price = Integer.parseInt(product_price);// Convert to Integer
map_final_products.put(int_product_price, product_name);// Add product and price in HashMap
}
// write out all the products we found
Reporter.log("All the prices and products we found: " +
map_final_products.toString()+ "\n", true);
// Get all the keys from Hash Map
Set<Integer> allkeys = map_final_products.keySet();
ArrayList<Integer> array_list_values_product_prices = new ArrayList<Integer>(allkeys);
// this will sort in ascending order lowest at the top and highest at the bottom
Collections.sort(array_list_values_product_prices);
As it is on console:
XYs are the actual brandnames
All the prices and products we found: {20720=XY,
11490=XY, 13490=XY, 15490=XY,
19490=XY, 21990=XY, 16490=XY, 18490=XY
20490=XY, 18990=XY, 20990=XY}
As I think my code just does not write out or collect when the price is the same with other brands(or with the same brands too). For example:
At the website there are more products for 13490.. and lots of for 18490.
How can I modify my code in order to get all the pairs even if they have same prices?
#Peter Santa, you should have product Name as your key instead of Price. So you can reverse the location. But this will not print the same product with the same or different price. Which I feel should be ok assuming, the same product will not have different prices on the same website.

How to calculate and make the result be displayed on HTML?

I have two values on my html: "Money" and "Time", and those values come from Session Storage, depending on what the person filled previously on another html page. So lets say the person filled that they need to pay $100 in 2 days.
What i'm trying to do, is to create a list, showing the number of payments, with the amount to be paid in each payment. Like the example below
MONEY: $100 / TIME: 2 Days
RESULT:
$50
$50
So if the person has 5 days, instead of 2, it would appear as:
$20
$20
$20
$20
$20
For some reason, when i try my code at codepen, using random numbers instead of the values i have on Session Storage, it works just fine, but when using the numbers from Session Storage, the result is always the same: I have a <li> with just one "topic" like:
MONEY: $100 / TIME: 2 Days
RESULT:
$50
I read somewhere that it might be because my values where stored as strings, but i don't know if thats correct, nor do i know how to undo that.
Current code below:
<p id="money-value"></p>
<p id="time-value"></p>
<div id="payments"></div>
<script>
const displayMoney = document.getElementById("money-value");
const storedMoney = sessionStorage.getItem("Money")
window.addEventListener("load", () => {
displayMoney.innerHTML = "Money: " + storedMoney
});
const displayTime = document.getElementById("time-value");
const storedTime = sessionStorage.getItem("Time")
window.addEventListener("load", () => {
displayTime.innerHTML = "Time: " + storedTime
});
var calc = storedMoney / storedTime;
for (let i = 0; i < storedTime; i++) {
var list = document.createElement("li");
list.innerText = `${calc}`;
document.getElementById("payments").appendChild(list);
}
sessionStorage.getItem("Time")
will only return the first item that matches the selector. This is similar to document.querySelector("selector"), which will only return the first instance of a match with that selector, whereas document.querySelectorAll("selector") will give you all the elements with that selector.
getItem does not have such an All alternative.
Instead, use keys. Check out some solutions for your problem in this post (probably the easiest is the forEach): Javascript: Retrieve all keys from sessionStorage?

How to remove array object cases after switch statement

I have a menu system in place and I have got some code for the checkout system to identify deals/discounts if certain items show up in the cart.
Here is the code so far:
var shampoo = false;
var dye = false;
var conditioner = false;
for (var i in cartArray) {
switch (cartArray[i].name) {
case 'Pantene Pro-V':
drinks = true;
break;
case 'Red Dye':
chicken = true;
break;
case 'Herbal Conditioner':
kebab = true;
break;
}
if (shampoo && dye && conditioner) {
console.log("yes");
// shoppingCart.removeItemFromCartAll(cartArray[i].name);
// window.location.reload(true);
break;
}
}
if (!shampoo || !dye || !conditioner) {
console.log("no");
}
The console log shows a yes in a full random cart so that's a positive but I tried to remove these three items together as a group but it doesn't work.
Here is the code for my remove function above:
obj.removeItemFromCartAll = function(name) {// removes all item name
for (var i in cart) {
if (cart[i].name === name){
cart.splice(i,1);
break;
}
}
saveCart();
};
I tried inserting this code:
shoppingCart.removeItemFromCartAll(cartArray[i].name);
Underneath each case but it ends up removing the item individually in the cart, not as a group of three.
Here is what the console looks like (array object):
yes
(4) [{…}, {…}, {…}, {…}]
0: {name: "Pantene Pro-V", price: 2.5, count: 1, total:
"2.50"}
1: {name: "Red Dye", price: 4, count: 1, total: "4.00"}
2: {name: "deodorant", price: 2.5, count: 1, total: "2.50"}
3: {name: "Herbal Conditioner", price: 1, count: 1, total: "1.00"}
length: 4
__proto__: Array(0)
Please help. Thank you.
Btw in the end I want to remove these three and add another item into the cart from the menu (like a package that has these three at a reduced price...FYI).
EDIT - commenting out this part here
shoppingCart.removeItemFromCartAll(cartArray[i].name);
removes the last item in the cart and substituting splice method for delete removes the whole cart and breaks the cart system
As I understand this code, it correctly removes only one item
cart.splice(i,1);
Here you provided 1 which means it will remove 1 item forward from the index provided as first argument. Try to change it to 3.
Worse case scenario would be if you have rumbled array and those 3 items are not after each other. Then at best you should make some property which would assign items to specific group and then use array's filter method to filter out items with group you want to remove
Use delete keyword
obj.removeItemFromCartAll = function(name) {// removes all item name
for (var item in cart) {
if (cart[item].name === name){
delete cart[item]
break;
}
}
saveCart();
};
"Underneath each case but it ends up removing the item individually in the cart, not as a group of three."
A group of three or three individual items is not important, what's important is that they are removed. Situations such as a customer having less than 3 sale items or none at all and/or not in the same order should be considered. A switch acting as a filter is a bad idea, you want to avoid hardcoding dynamic data (I'm assuming that the items in the cart would be different for each customer and that the sale items eventually change as well.)
Demo Outline
list An Array of Objects representing the contents of a customer's cart.
sale An Array of Objects representing the items currently on sale.
Convert both arrays into Maps.
var discount = convertToMap(list, "name")
var customer = convertToMap(sale, "name")
Compare discount and customer Maps to each other and merge each matching key/value pair from discount to customer.
Result is a Map with this pattern:
`[["Muffin Mix - Raisin Bran", {"name":"Muffin Mix - Raisin Bran","price":5.85,"qty":1,"total":2.92,"saved":2.93}], ...]`
Demo
// Sale Items - Note the "total" and "saved" values
let sale = [
{"name":"Flavoring - Orange","price":4.57,"qty":1,"total":2.00,"saved":2.57},
{"name":"Muffin Mix - Raisin Bran","price":5.85,"qty":1,"total":2.92,"saved":2.93},
{"name":"Pepsi - Diet, 355 Ml","price":3.63,"qty":1,"total":1.81,"saved":1.82}
];
// Cart Items - This represents the customer's cart
let cart = [
{"name":"Plastic Arrow Stir Stick","price":0.75,"qty":1,"total":0.75,"saved":0},
{"name":"Veal - Round, Eye Of","price":22.91,"qty":1,"total":22.91,"saved":0},
{"name":"Calypso - Pineapple Passion","price":8.69,"qty":1,"total":8.69,"saved":0},
{"name":"Sloe Gin - Mcguinness","price":33.27,"qty":1,"total":33.27,"saved":0},{"name":"Wine - Sake","price":28.47,"qty":1,"total":28.47,"saved":0},
{"name":"Dried Figs","price":1.78,"qty":1,"total":1.78,"saved":0},
{"name":"Pepsi - Diet, 355 Ml","price":3.63,"qty":1,"total":3.63,"saved":0},
{"name":"Olives - Moroccan Dried","price":15.17,"qty":1,"total":15.17,"saved":0},
{"name":"Muffin Mix - Raisin Bran","price":5.85,"qty":1,"total":5.85,"saved":0}
];
/*
# convertToMap(array, key)
# Params: array [Array of Objects]..(ex. list)
# key [String]..............(ex. "name")
# Converts an Array of Objects to a MAP
# iNPUT: [{key,...}, {key,...}, {key,...}], key
# ~~~~~~~~~~~~~~===~~~~~~~~~~~~~~~
# OUTPUT: [[key, {key,...}], [key, {key,...}], [key, {key,...}]]
*/
const convertToMap = (array, key) => {return new Map(array.map(item => [item[key], item]));};
// Get a Map of sale
const discount = convertToMap(sale, 'name');
// Get a Map of cart
const customer = convertToMap(cart, 'name');
/*
# mergeMaps(mapA, mapB)
# Params: mapA [Map]...smaller Map...(ex. [[...], [...]])
# mapB [Map]...larger Map....(ex. [[...], [...]])
# Compares MapA to MapB
# If any matches by value occur,
# replace MapB key/value with MapA key/value
*/
const mergeMaps = (mapA, mapB) => {
for (let key of mapB.keys()) {
if (mapA.has(key)) {
mapB.set(key, mapA.get(key));
}
}
return mapB;
};
let shoppingA = mergeMaps(discount, customer);
console.log(shoppingA.get("Sloe Gin - Mcguinness"));
console.log("~~~~~~~~~~~~~~~~~~~~~-====-~~~~~~~~~~~~~~~~~~~~~");
// [OPTION] Convert new Map to a 2D Array
let shoppingB = Array.from(mergeMaps(discount, customer));
console.log(shoppingB);

Generate combination of products given a total price limit

I have an array of products id, and 2 arrays with product id in key and price and unique flag in values.
I would like to have all unique combinations of products under a given total limit price :
a product could be several times in combination, except if it is flagged as unique
combination should be sorted by product id
a valid combination is one to the which we can't add product
Sample:
products = [1, 2, 3];
productPrices = {1:10, 2:15, 3:10};
productUnique = {1:true, 2:false, 3:false};
limitPrice = 40;
expected result = [[1,2,2],[1,2,3],[1,3,3,3],[2,2,3],[2,3,3],[3,3,3,3]];
How can I obtain this result in javascript if possible ?
Thanks for the help.
I would suggest another format for your input, so it is a single array of objects, where each of those objects has an id, price and unique property.
Then with that array of objects and the limit price, use recursion to select at each level of recursion a product to be added to a series of products until none can be added. At that time add the selected product list to a results array.
When selecting a product, determine which products can still be selected in the next level of recursion: when a unique product was selected, then don't pass that on as a selection possibility to the next level.
To avoid duplicates, once a product is no longer selected from, don't come back to it at deeper recursion levels; so pass on a shorter product list in recursion when it is decided not to pick the same product again. The recursion ends when the cheapest, still available product is more expensive than the amount that is still available.
Here is a snippet:
function intoOne(products, productPrices, productUnique) {
return products.map( (id) => ({
id,
price: productPrices[id],
unique: productUnique[id]
}));
}
function combinations(products, limitPrice) {
const results = [];
function recurse(sel, products, minPrice, maxPrice) {
products = products.filter(p => p.price <= maxPrice);
if (!products.length && minPrice > maxPrice) return results.push(sel);
products.forEach( (p, i) => {
recurse(sel.concat(p.id), products.slice(i+p.unique),
minPrice, maxPrice-p.price);
minPrice = Math.min(minPrice, p.price);
});
}
recurse([], products, limitPrice, limitPrice);
return results;
}
var products = [1, 2, 3],
productPrices = {1:10, 2:15, 3:10},
productUnique = {1:true, 2:false, 3:false},
limitPrice = 40;
// Combine product characteristics in more suitable structure
products = intoOne(products, productPrices, productUnique);
// Call main algorithm
var result = combinations(products, limitPrice);
console.log(JSON.stringify(result));
You could take an iterative and recursive approach by checking the sum, length and unique parameter for next call of the same function with changed index or temporary items.
If the sum is smaller than the limit, the temporary result is added to the result set.
function iter(index, temp) {
var product = products[index],
sum = temp.reduce((s, k) => s + prices[k], 0);
if (sum + prices[product] > limit) {
result.push(temp);
return;
}
if (!unique[product] || temp[temp.length - 1] !== product) {
iter(index, temp.concat(product));
}
if (index + 1 < products.length) {
iter(index + 1, temp);
}
}
var products = [1, 2, 3],
prices = { 1: 10, 2: 15, 3: 10 },
unique = { 1: true, 2: false, 3: false },
limit = 40,
result = [];
iter(0, []);
console.log(JSON.stringify(result));

Find separation values from a starting node

I found on some online coding exercises and this one looks really cool and I wanted to give it a shot.
Problem Statement
Quinn is a pretty popular, and extremely modest guy. Other students measure their popularity in a unit called QDist.
One can calculate their QDist value by finding the degrees of separation between their self and Quinn. For example:
If Quinn is friends with Dave, and Dave is friends with Travis, then Dave's QDist value is 1, and Travis is 2.
Output
name QDist for each person entered ordered alphabetically by name.
In the event that a person is not connected to Quinn in anyway, output name uncool
Given a list of friendships, list each person and their QDist value in alphabetical order.
Sample Input/output
10
Alden Toshiko
Che Kortney
Che Dorian
Ronda Lindell
Sharon Alden
Dorian Quinn
Owen Sydnee
Alden Che
Dorian Tyra
Quinn Ally
Output
Alden 3
Che 2
Dorian 1
Kortney 3
Lindell uncool
Ally 1
Owen uncool
Quinn 0
Ronda uncool
Sharon 4
Sydnee uncool
Toshiko 4
Tyra 2
My Approach
Firstly, I don't want the answer I just want a hint or some guidance on how I should approach the problem in javascript (as its the language i'm the most familiar with). My thought was to break the program into an object and arrays, and try to create a family relationship between each name, sort of as a nested object or perhaps an array. Then I could use some sort of recursion to find how deep the array or object goes.
What would be the best approach?
From the input you could create a list of persons. It could be an object, where each key is a person's name, and the corresponding value is an array of names, representing the friends of that person. Of course you should make sure that when you add B as a friend of A, you must also add A as a friend of B.
For the example input, the above structure would look like this:
{
"Alden": ["Toshiko","Sharon","Che"],
"Toshiko": ["Alden"],
"Che": ["Kortney","Dorian","Alden"],
"Kortney": ["Che"],
"Dorian": ["Che","Quinn","Tyra"],
"Ronda": ["Lindell"],
"Lindell": ["Ronda"],
"Sharon": ["Alden"],
"Quinn": ["Dorian","Ally"],
"Owen": ["Sydnee"],
"Sydnee": ["Owen"],
"Tyra": ["Dorian"],
"Ally": ["Quinn"]
}
Then keep track of a list of names, starting with just Quinn, and also a distance, starting at 0.
Then for each name in that list, assign the current distance as their QDist value. Then find their friends and put them all together. Remove names that have already received a QDist value.
Then increase the distance, and repeat the above for that new list of names.
Keep repeating until the list of names is empty.
Note that if you do things in the right order, you can replace a persons list of friends by the QDist value. So the above structure would change after the first two iterations to:
{
"Alden": ["Toshiko","Sharon","Che"],
"Toshiko": ["Alden"],
"Che": ["Kortney","Dorian","Alden"],
"Kortney": ["Che"],
"Dorian": 1,
"Ronda": ["Lindell"],
"Lindell": ["Ronda"],
"Sharon": ["Alden"],
"Quinn": 0,
"Owen": ["Sydnee"],
"Sydnee": ["Owen"],
"Tyra": ["Dorian"],
"Ally": 1
}
When the algorithm finishes, you have:
{
"Alden": 3,
"Toshiko": 4,
"Che": 2,
"Kortney": 3,
"Dorian": 1,
"Ronda": ["Lindell"],
"Lindell": ["Ronda"],
"Sharon": 4,
"Quinn": 0,
"Owen": ["Sydnee"],
"Sydnee": ["Owen"],
"Tyra": 2,
"Ally": 1
}
Now the remaining friends arrays need to be replaced with "uncool", as apparently the corresponding people have no connection with Quinn. Also the list needs to be sorted.
Spoiler warning!
Here is a working snippet:
// Get input as text
var input = `10
Alden Toshiko
Che Kortney
Che Dorian
Ronda Lindell
Sharon Alden
Dorian Quinn
Owen Sydnee
Alden Che
Dorian Tyra
Quinn Ally`;
// Build persons list with friends list
var persons =
// Take the input string
input
// Split it by any white-space to get array of words
.split(/\s+/)
// Skip the word at position 0: we don't need the line count
.slice(1)
// Loop over that array and build an object from it
.reduce(
// Arguments: obj = result from previous iteration
// name = current name in names array
// i = index in that array
// names = the whole array being looped over
(obj, name, i, names) => (
// Get the list of friends we already collected for this name.
// Create it as an empty array if not yet present.
obj[name] = (obj[name] || [])
// Add to that list the previous/next name, depending
// whether we are at an odd or even position in the names array
.concat([names[i%2 ? i-1 : i+1]])
// Use the updated object as return value for this iteration
, obj)
// Start the above loop with an empty object
, {});
// Now we have a nice object structure:
// { [name1]: [friendName1,friendName2,...], [name2]: ... }
// Start with Quinn as the only person we currently look at.
var friends = ['Quinn'];
// Increment the distance for each "generation" of friends
// until there are none left.
for (var i = 0; friends.length; i++) {
// Replace the friends list with a new list,
// while giving the friends in the current list a distance
friends =
// Start with the current list of friends
friends
// Loop over these friends.
// Only keep those that still have a friends array (object) assigned to them,
// since the others were already assigned a distance number.
.filter(friend => typeof persons[friend] === "object")
// Loop over those friends again, building a new list of friends
.reduce((friends, friend, k) => [
// Add this friends' friends to the new list
friends.concat(persons[friend]),
// ... and then replace this friends' friend list
// by the current distance we are at.
persons[friend] = i
// Return the first of the above two results (the new list)
// for the next iteration.
][0]
// Start with an empty array for the new friends list
, []);
}
// Now we have for each person that connects to Quinn a number:
// { [name1]: number, ... }
// Convert this to a format suitable to output
var result =
// Get list of names from the object (they are the keys)
Object.keys(persons)
// Sort that list of names
.sort()
// Loop over these names to format them
.map(name =>
// Format as "name: distance" or "name: uncool" depending on whether there
// still is an array of friends (object) in this entry
name + ': ' + (typeof persons[name] == 'object' ? 'uncool' : persons[name]));
// Output the result in the console
console.log(result);
And a more verbose, but easier to understand version:
// Get input as text
var input = `10
Alden Toshiko
Che Kortney
Che Dorian
Ronda Lindell
Sharon Alden
Dorian Quinn
Owen Sydnee
Alden Che
Dorian Tyra
Quinn Ally`;
// Build persons list with friends list
// Take the input string
var persons = input;
// Split it by any white-space to get array of words
persons = persons.split(/\s+/)
// Skip the word at position 0: we don't need the line count
persons = persons.slice(1)
// Loop over that array and build an object from it
var obj = {}; // Start loop with an empty object
for (var i = 0; i < persons.length; i++) {
var name = persons[i]; // name = current name in names array
// Get the list of friends we already collected for this name.
// Create it as an empty array if not yet present.
if (obj[name] === undefined) obj[name] = [];
// Add to that list the previous/next name, depending
// whether we are at an odd or even position in the names array
obj[name].push(persons[i%2 === 1 ? i-1 : i+1]);
}
// Assign result to persons
persons = obj;
// Now we have a nice object structure:
// { [name1]: [friendName1,friendName2,...], [name2]: ... }
// Start with Quinn as the only person we currently look at.
var friends = ['Quinn'];
// Increment the distance for each "generation" of friends
// until there are none left.
for (var i = 0; friends.length !== 0; i++) {
// Loop over those friends, building a new list of friends
// Start with an empty array for the new friends list
var newFriends = [];
for (var k = 0; k < friends.length; k++) {
var friend = friends[k];
// Only consider those that still have a friends array (object) assigned to them,
// since the others were already assigned a distance number.
if (typeof persons[friend] === "object") {
// Add this friends' friends to the new list
newFriends = newFriends.concat(persons[friend]);
// ... and then replace this friends' friend list
// by the current distance we are at.
persons[friend] = i;
}
};
// Make the new list the current list:
friends = newFriends;
}
// Now we have for each person that connects to Quinn a number:
// { [name1]: number, ... }
// Convert this to a format suitable to output
// Get list of names from the object (they are the keys)
var result = Object.keys(persons);
// Sort that list of names
result.sort();
// Loop over these names to format them
for (var i = 0; i < result.length; i++) {
var name = result[i];
// Format as "name: distance" or "name: uncool" depending on whether there
// still is an array of friends (object) in this entry
if (typeof persons[name] == 'object') {
result[i] = name + ': uncool';
} else {
result[i] = name + ': ' + persons[name];
}
}
// Output the result in the console
console.log(result);
If i had to solve this problem,
First I would create an array and initialise it with student who are 1 with Quinn by finding rows (elements) studentX ←→ Quinn in original array.
Then I would search recursively those who are level n with quinn by finding rows studentX ←→ student(n-1)FromQuinn
My attempt to understand
var persons = input.split(/\s+/).slice(1).reduce(function(obj,name,i,names){
return (obj[name] = (obj[name] || []).concat([names[i%2 ? i-1 : i+1]]), obj);
},{});
First input.split(/\s+/).slice(1) Gives us an array with all of the names in it.
Now
(obj[name] = (obj[name] || []).concat([names[i%2 ? i-1 : i+1]]), obj);
obj is set by default to due to {} according to the reduce method property.
name is current value which is basically going from Alden all the way to Ally. i will go from 1-10 and names is the array
Now we are saying set obj[name] = obj[name].concat([names[i%2 ? i-1 : i+1]]),obj); IF this is possible. If this isn't possible set obj[name] = [].concat([names[i%2 ? i-1 : i+1]]),obj);. This is my interpretation from reading up on ||
Example iteration
first obj = {}, and name will be Alden
so the type Alden i.e persons = { Alden: ..} will be obj[Alden].concat(names[2],obj), it will be 2, since 1 mod 2 doesn't get reached.
Now there is where I am a bit confused... what exactly is the ,obj doing here..? am I interpreting this right?

Categories

Resources