How to find duplicates, count elements in array using javascript/jquery - javascript

I have a form in HTML. In this form, I can build catalog preferences.
When I'm done with that I can click on save button and build a next one. The result is saving in an array.
When I have more than one saved catalog(sku=stock keeping unit) in my array it's possible that there are some duplicates. How can I remove the duplicates and count them (The quantity should stay even if there is a duplicate)?
Jsfiddle
Array(Array(
0:5016s18gercol, //sku(stock keeping unit)
1: 100, //quantity
2: 5017ext10002, //extra sku for extra costs(cataloge in color)
3: 1
),
Array(
0:5016s43gerbw, //sku
1: 100, //quantity
2: 5017ext10001,//extra sku for extra costs(catalog own cover)
3: 1 //quanitity extra costs
),
Array(
0: "5016s43gercol" //sku
1: "400" //quantity
2:"5017ext10001" //extra sku (own cover)
3:"1" //quantity sku
4:"5017ext10002" //extra sku (in color)
5:"1" //quantity sku
)
)
This is what i get. It should look like this:
array(5016s18gercol,
500,
5017ext10002,
2,
5017ext10001,
2)
Every sku is unique so i cant have two same sku's. I have to count them if there are more than one.

Use array.prototype.map and array.prototype.some:
var values = [
{ name: 'someName1' },
{ name: 'someName2' },
{ name: 'someName4' },
{ name: 'someName2' }
];
var valueArr = values.map(function(item){ return item.name });
var isDuplicate = valueArr.some(function(item, idx){
return valueArr.indexOf(item) != idx
});
console.log(isDuplicate);

Related

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

Return json array if matches input

Need help:
I have my JSON formatted array. What I can't seem to wrap my head around is how to all the contents of said array when it matches user input. I can display the whole array and i can check if the input is in the array.
Code:
//user input
var product = document.getElementById('product').value;
var price = document.getElementById('price').value;
var quantity = document.getElementById('quantity').value;
//Products
var viewInventory = [{
id : 'a',
name : 'iphone',
model : 10,
price : 900,
quantity : 25
}, {
id: 'b',
name : 'pixel',
model : 1,
price : 800,
quantity : 40
},{
id: 'c',
name : 'pants',
model : 8,
price : 700,
quantity : 80
},{
id: 'd',
name : 'essential',
model : 10,
price : 900,
quantity : 25
}];//end of viewInventory
console.log(viewInventory);//just testing to see it JSON obj works
function hello(){
var item;
for (var i = 0; item = viewInventory[i].name; i++){
console.log(item);
// console.log(viewInventory[i].name)
if (product === item){
console.log(viewInventory[i]);
console.log(item + "This is input");
// document.write(myTable);
}
}
Problem:
Below is the problem from my book ( i am self learning).
Pulling data from a file into a complex data structure makes parsing much simpler. Many programming languages support the JSON format, a popular way of representing data.
Create a program that takes a product name as input and retrieves the current price and quantity for that product.The product data is in a data file in the JSON format and looks like this:
{
_"products" : [
_{"name": "Widget", "price" : 25.00, "quantity": 5 },
__{"name": "Thing", "price": 15.00, "quantity": 5},
__{"name": "Doodad", "price": 5.00, "quantity": 10}
__]
}
Print out the product name, price, and quantity if the product is found. If no product matches the search, state, that no product was found and start over.
Example output
What is the product name? iPad
Sorry, that product was not found in our inventory
What is the product name? Widget
Name: Widget
Price: $25.00
Quantity on hand: 5
Constraints
The file is in the JSON format. Use a JSON parser to pull the values out of the file.
If no record is found, prompt again.
Challenges
Ensure that the product search is case-insensitive.
When a product is not found, ask if the product should be added. If yes, ask for the price and the quantity, and save it in the JSON file. Ensure the newly added product is immediately available for searching without restarting the program.
you can use the Array.prototype.filter function:
var product = document.getElementById('product').value;
var price = document.getElementById('price').value;
var quantity = document.getElementById('quantity').value;
var matchingProducts = viewInventory.filter((v)=>v.name.indexOf(product)>-1);
if(!matchingProducts.length) alert('Sorry, that product was not found in our inventory');
else {
alert(
matchingProducts.reduce(
(c,i)=>c+i.name+' found with price='+i.price+' and the quantity='+i.quantity+'\n',
''
)
);
}

Compare 'order' to 'products' array and print product names if in the order?

I have an array of products:
const products = {
{
id: item1,
name: 'My product',
price: 100
},
{
id: item2,
name: 'My other product',
price: 200
},
{
id: item3,
name: 'My other other product',
price: 150
}
}
I also have an order state which says which and how many products are in the order. In this instance there is 1 item1 and 2 item2 in the order:
const orderState = {
item1: 1,
item2: 2
}
How can I render the prodcut name and number of times its in the order? Im using React but I think vanilla JS is all thats needed for the solution.
My HTML output needs to be something like:
<ul>
<li>My product x1 = $1</li>
<li>My other product x2 = $4</li>
</ul>
The way you're storing your data is what seems to be giving you difficulty. First, make the array of products an actual array:
const products = [
{
id: item1,
name: 'My product',
price: 100
}, //...
];
Additionally, what is that item1 value? Is that an actual ID of some kind, like an integer? That's what you'll use to identify the products later.
Then for your "order state", create an object which holds an array of references to the products. Something like this:
const orderState = {
products: [
{
productID: item1,
quantity: 1
},
{
productID: item2,
quantity: 2
}
]
}
Now that you have a more sensible data structure, you can more easily operate on that structure. There are a variety of ways to build your output, and how you do it may depend heavily on what other tools you're using (such as template engines and such). But just to demonstrate the logic, let's build a simple string:
var output = '<ul>';
for (var i = 0; i < orderState.products.length; i++) {
var product = {};
for (var j = 0; j < products.length; j++) {
if (products[j].id == orderState.products[i].id) {
product = products[j];
break;
}
}
output += '<li>' + product.name + ' x' + orderState.products[i].quantity + ' = $' + (product.price * orderState.products[i].quantity) + '</li>';
}
output += '</ul>';
From this you can refactor and improve as needed. For example, the logic to find the product based on its id can be extracted into its own function, or perhaps even reduced to a one-liner using built-in JavaScript functionality or framework functionality. (underscore.js is good for functionality like that.)
But the basic idea is to keep the data structures sensibly organized. Then the code which operates on those structures becomes trivial.
With below solution you can get the names of selected products as per your question statement.
let productsOrderedIds = Object.keys(orderState);
let proNames = [];
for(let pro of products) {
if(productsOrderedIds.indexOf(pro.id) !== -1){
proNames.push(pro.name);
}
}
console.log(proNames);

remove and replace item from object in array javascript

I have read and tried all of the posts of SO on this subject, but for some reason none of the answers are providing the desired effect.
I have written a shopping basket program and once the user clicks the'Buy now' button I wish to make POST request containing an object with the users order.
Problem
The user has the option to purchase three different items. Each time the user clicks on an item, which is a html input box, to increase the amount they wish to purchase I want to update the object to only contain the latest amount chosen.
In its simplest format the basket, when initiated, looks like this :
var basket = {items:[
{item:"Trousers", quantity:1, cost:"10"},
{item:"Trainers", quantity:1, cost:"5"},
{item:"Jacket", quantity:1, cost:"30"}
]}
Each time the user clicks the input button I wish for the basket to be updated so if the user clicked to increase the jacket to a quantity of 3, and the trousers to 4 I want the object to look like this:
var basket = {items:[
{item:"Trousers", quantity:4, cost:"40"},
{item:"Trainers", quantity:1, cost:"5"},
{item:"Jacket", quantity:3, cost:"90"}
]}
Then if a user decides to reduce the number of trousers by 1, to 3, I would want the basket.items object to look like this:
var basket = {items:[
{item:"Trousers", quantity:3, cost:"30"},
{item:"Trainers", quantity:1, cost:"5"},
{item:"Jacket", quantity:3, cost:"90"}
]}
I have written the code for all the calculations etc. so this is not the issue but the issue is to update basket.items to only contain the three items listed above at once, with the latest data.
I cannot use the filter method as this needs to work in older versions of IE. I have tried all solutions listed in this and this along with many more but none of these answers are providing the solution I am looking for.
Let me know if any further information is required.
try this:
var basket = {
items: [
{
item: "Trousers",
quantity: 1,
cost: "10"
}, {
item: "Trainers",
quantity: 1,
cost: "5"
}, {
item: "Jacket",
quantity: 1,
cost: "30"
}]
};
function updateBasket(item) {
basket.items = basket.items.map(function (product) {
if (product.item == item.item) return item;
else return product;
});
}
updateBasket({
item: "Jacket",
quantity: 9,
cost: "30"
});
updateBasket({
item: "Trainers",
quantity: 9,
cost: "30"
});
console.log(basket)
Don't know if for you having an array of objects is mandatory if that's not the case you can structure your data differently, for instance
basket = { items : { item_1 : { quantity: 1, cost: 1 } } }
so updating the basket it will be simply
function updateBasket(item, value) {
// item -> item_1
// value - > { quantity: 2, cost: 2}
basket['items'][item] = value;
}
To be honest, I think the problem could be solved if you kept your data in a little different way. For example, something like this
var products = {
trousers:0,
jackets:0,
trainers:0,
};
var prices = {
trainers:5,
jackets: 30,
trousers: 10
}
//to increase the amount of products after user event
products.jackets +=2;
products.trainers +=3;
products.trousers +=1;
//finally generate your desired format
var basket = {items:[]};
for(product in products){
basket.items.push({
item: product,
quantity: products[product],
cost: products[product]*prices[product]
});
}
console.log(basket);
You can see that basket is now in your desired format :)
Cost should be a number and not string.
If you are not keeping a global object for what is the price of 1 item then once you have updated your basket object you will loose the information on price of 1 item and you wouldn't know how much to increase the price.
Considering same, below would be my recommendation of changes:
var basket = {items:[
{item:"Trousers", quantity:4, itemCost:40, totalCost:40},
{item:"Trainers", quantity:1, itemCost:5, totalCost:5},
{item:"Jacket", quantity:3, itemCost:90, totalCost:90},
]}
function updateQuantity(itemName, qIncreaseBy, qDecreaseBy){
console.log(basket);
for(var propt in basket.items){
if(basket.items[propt].item == itemName){
if(qIncreaseBy != 0){
basket.items[propt].quantity = (basket.items[propt].quantity + 1);
basket.items[propt].totalCost = (basket.items[propt].totalCost + basket.items[propt].itemCost);
} else{
basket.items[propt].quantity = (basket.items[propt].quantity - 1);
basket.items[propt].totalCost = (basket.items[propt].totalCost - basket.items[propt].itemCost);
}
break;
}
}
console.log(basket);
}
Usage:
updateQuantity("Trainers", 0, 1); //To add item
updateQuantity("Trainers", 1, 0) //To remove item

Accessing an element in an array within an array in JavaScript

Pastebin of index.html: http://pastebin.com/g8WpX6Wn (this works but with some broken img links & no css).
Zip file if you want to see whole project:
I'm trying to dynamically change the contents of a div when I click an image. The image has it's respective id (the first index in the inner array) within the first inner array there's another array (index 3). I want to populate my div (id="articleLinks") with those links using JQuery when the image is clicked.
JavaScript & JQuery:
The tube array. *Note: the first index of each element in tubeArray is the ID & the news articles aren't linked to anything particular. Only interested in tubeArray[0] & tubeArray[4]
var tubeArray = [
['UQ', -27.495134, 153.013502, "http://www.youtube.com/embed/uZ2SWWDt8Wg",
[
["example.com", "Brisbane students protest university fee hikes"],
["example.com", "Angry protests over UQ student union election"],
]
],
['New York', 40.715520, -74.002036, "http://www.youtube.com/embed/JG0wmXyi-Mw",
[
["example.com" , "NY taxpayers’ risky Wall Street bet: Why the comptroller race matters"]
]
],
['To The Skies', 47.09399, 15.40548, "http://www.youtube.com/embed/tfEjTgUmeWw",
[
["example.com","Battle for Kobane intensifies as Islamic State uses car bombs, Syrian fighters execute captives"],
["example.com","Jihadists take heavy losses in battle for Syria's Kobane"]
]
],
['Fallujah', 33.101509, 44.047308, "http://www.youtube.com/embed/V2EOMzZsTrE",
[
["example.com","Video captures family cat saving California boy from dog attack"],
["example.com","Fines of £20,000 for dogs that chase the postman"]
]
]
];
A for loop which goes through each element in tubeArray then assigns id to the first index. Also an image that calls the function myFunctionId which takes the parameter this.id.
for (i = 0; i < tubeArray.length; i++) {
var id = tubeArray[i][0];
//other code
'<img src="img.png" onclick="myFunctionId(this.id);" id="' + id + '">' +
//other code
}
function myFunctionId (id) {
journal = id;
alert(journal) //just a test
//I want to search through tubeArray with the id and find the matching inner array.
//I then want to loop through the innerArray and append to my html a link using JQuery.
for (j = 0; i < innerArray.length; j++){
//supposed to get "www.linkX.com"
var $link = ;
//supposed to get "titleX"
var $title = ;
//change the content of <div id="articleLinks">
$('#articleLinks').append('<a href=$link>$title</a><br>');
}
}
HTML:
<div id="articleLinks">
Example Link<br>
</div>
Any help would be greatly appreciated. I've tried to simplify & cut out as much as I can so it's readable.
probably this might help: make yourself a map like
var tubeArray = [
[ // tubeArray[0]
'id', // tubeArray[0][0]
int, // tubeArray[0][1]
int, // tubeArray[0][2]
[ // tubeArray[0][3]
[ // tubeArray[0][3][0]
"www.link1.com", // tubeArray[0][3][0][0]
"title1" // tubeArray[0][3][0][1]
],
[ // tubeArray[0][3][1]
"www.link2.com", // tubeArray[0][3][1][0]
"title2" // tubeArray[0][3][1][1]
]
]
],
etc.
don't know whether this helps, but four dimensional arrays are brain-breaking ....
[edit]
... and thus go for a more OO like approach:
var tubeArray = [
'id' : { // tubeArray[id] or tubeArray.id
'a': int, // tubeArray.id.a
'b': int, // tubeArray.id.b
'entries': [ // tubeArray.id.entries
{ // tubeArray.id.entries[0]
'url': "www.link1.com", // tubeArray.id.entries[0].url
'title': "title1"
},
{ // tubeArray.id.entries[1]
'url': "www.link2.com", // tubeArray.id.entries[1].url
'title': "title2" ...
}
]
] ,
First you need to loop over tubeArray then go 4 deep and loop over the Array of Arrays at that level. Of course, you loop over those inner Arrays and get Elements 0 and 1.
$.each(tubeArray, function(z, o){
$.each(o[4], function(i, a){
$.each(a, function(n, v){
$('#articleLinks').append("<a href='"+v[0]+"'>"+v[1]+'</a>'); // use CSS to break lines
});
});
}

Categories

Resources