Objects array in Javascript - javascript

I'm studying Javascript and I have this sample program that shows how to use a module.
There is a "products" array and I couldn't find out what "products[productName]" is meant to do in this program. If I understand correctly, in Javascript, an array always uses numbered indexes and doesn't work if you use named indexes.
As much as I expect, like this objects array is made in this program.
products = [ {productName: 0,} ]
I'm looking forward to helping me. Thank you in advance.
var store = {};
shop.cart = (function() {
var products = [];
function addProduct(productName) {
if(!products[productName]) {
// If the product is not added into the shopping cart, add it there.
products[Productname] = 0;
}
// Raise the number of products by one
products[productName]++;
}
function totalProducts() {
var amount = 0;
for(var productName in products) {
amount += products[Productname];
}
return amount;
}
// interface
return {
add: addProduct,
productAmount: productTotal
};
})();
store.cart.add("keksi");
store.cart.add("keksi");
store.cart.add("apple");
console.log(store.cart.productAmount()); // 3

Related

how can I filter an array without losing the index?

I have two really long arrays containing "picture names" and "picture files". The first one represents the actual name of the pictures, while the second one is just the file name. For example:
picturenames[0] = '0 - zero';
picturenames[1] = '1 - one';
picturenames[2] = '1 o\'clock';
...
picturefiles[0] = 'numbers-zero.jpg';
picturefiles[1] = 'numbers-one.jpg';
picturefiles[2] = 'time-1.jpg';
...
I have about 1000 items in each array in several languages (the picture files are always the same). I'm "recycling" these arrays from the previous application to save some time and avoid rewriting everything anew.
Desirable functionality: using the user's input in a textbox I want to filter the picturenames array and then show the correspondant picturefiles image.
The issue I'm facing: when I filter the picturenames array I lose the index and I can't "reach" the picture file name.
This is the code I'm using to filter the picturenames array.
var matches = picturenames.filter(function(windowValue){
if(windowValue) {
return windowValue.indexOf(textToFindLower) >= 0;
}
});
What would be the best way to do this?
UPDATE: the solution proposed by Ahmed is the best one, but for time reasons and negligible performance issues I'm just using a for loop to search trough the array, as follows:
var matchesCounter = new Array();
for (i = 0; i < picturenames.length; i++) {
if (picturenames[i].indexOf(textToFindLower) >= 0) {
matchesCounter.push(i);
}
}
console.log(matchesCounter);
for (i = 0; i < matchesCounter.length; i++) {
console.log(picturenames[i]);
console.log(picturefiles[i]);
}
Try this:
const foundIndicies = Object.keys(picturenames).filter(pictureName => {
pictureName.includes(textToFindLower)
});
// reference picturefiles[foundIndicies[0]] to get the file name
Though, it would be far nicer to have both the name and the file in a single object, like so:
const pictures = [
{
name: '0 - zero',
file: 'numbers-zero.jpg',
},
{
name: '1 - one',
file: 'numbers-one.jpg',
}
];
const foundPictures = pictures.filter(picture => picture.name.includes('zero'));
if (foundPictures[0]) console.log(foundPictures[0].file);
You can add one property index during the filtering time, then later on you can use the index.
var matches = picturenames.filter(function(windowValue, index){
if(windowValue) {
windowValue.index = index;
return windowValue.comparator(textToFindLower) >= 0;// Need to define comparator function
}
});
Later on you can access by using like follows:
picturefiles[matches[0].index]
However, the solution will work on object, not primitive type string.
If your data type is string, then you have to convert as object and put the string as a property value like name. The snippet is given below:
var picturenames = [];
var picturefiles = [];
picturenames.push({name:'0 - zero'});
picturenames.push({name:'1 - one'});
picturenames.push({name:'1 o\'clock'});
picturefiles.push({name:'numbers-zero.jpg'});
picturefiles.push({name:'numbers-one.jpg'});
picturefiles.push({name: 'time-1.jpg'});
var textToFindLower = "0";
var matches = picturenames.filter(function(windowValue, index){
if(windowValue) {
windowValue.index = index;
return windowValue.name.indexOf(textToFindLower) >= 0;
}
});
console.log(matches);

How to check if a item/value already exists in Local Storage

I am working on a shopping cart application were users can click an Add to Cart button that will then add the specific item to local storage. When the user is adding a product to their shopping cart I need to be able to check to see if that specific item/value/product already exists in local storage. If it does, I need to increase only the count of that item/value/product by 1. If not, I need to add an entirely new item/value/product to local storage with a count of 1.
How can I find if an item already exists in local storage and compare it to the id of the current product that a user is attempting to add to their cart? My first few attempts failed miserably and have yet to find anything online that is helping with this issue. Is there a better way of going about this? Any assistance is appreciated. Even a good link to a good page would be extremely helpful.
Below is the code I have to attempt in checking for if the productid being added matches any of the productids in local storage. Basically if the productId that is being added matches the productId of an item in local storage simply add 1 to the quantity.
var retrieverObject = localStorage.getItem('Products');
var retrieveObject = JSON.parse(retrieverObject);
var data = {};
var productId = currentNode.name;
var product = currentNode;
data.productPrice = product.parentNode.previousSibling.previousSibling.id;
data.productId = productId;
var length = retrieveObject.length;
console.log(length);
for(var i = 0; i<length; i++){
if(retrieveObject[i].productId == data.productId){
var quantity = retrieveObject[i].quantity;
retrieveObject.push({"productPrice": data.productPrice, "productId": data.productId, "quantity": quantity++});
}else{
retrieveObject.push({"productPrice": data.productPrice, "productId": data.productId, "quantity": 1});
}
}
console.log(retrieveObject);
localStorage.setItem('Products', JSON.stringify(retrieveObject));
var retrievedObject = localStorage.getItem('Products');
var obj = JSON.parse(retrieverObject);
var len = obj.length;
console.log(len);
for(var i=0; i<len;i++){
console.log(obj[i]['productPrice']+", "+obj[i]['productId']);
}
}
}
There are a few issues. First, I am not entirely certain that the productId of the retrieved object is being compared to the one that is being added. Secondly, the for(var i = 0; i<length; i++){} definitely does not seem to be doing what was expected and is multiplying the number of items being added by 2. Thirdly, which may relate to the second issue, the retrieveObject.push() is not updating the quantity of the product but is adding an entire new entry to local storage. The given answers did not seem to be working for me before so this is what I have been working on. Any new answers or general help would be great.
PT 2. : So I am having an issue with the first entry into the local storage. Without noting that when there is nothing in local storage and you make a call to get the items in it, it returns null or undefined. So currently I have it set up like this:
if(localStorage.getItem("Products") === null || localStorage.getItem("Products") === undefined){
var data = {};
var productId = currentNode.name;
var product = currentNode;
data.productPrice = product.parentNode.previousSibling.previousSibling.id;
data.productId = productId;
var obj = [];
obj = obj[data.productId] = {
productPrice: data.productPrice,
count: 1
};
console.log(obj);
localStorage.setItem('Products', JSON.stringify(obj));
}
else{
var retrieverObject = localStorage.getItem('Products');
var retrieveObject = JSON.parse(retrieverObject);
var data = {};
var productId = currentNode.name;
var product = currentNode;
data.productPrice = product.parentNode.previousSibling.previousSibling.id;
data.productId = productId;
if(retrieveObject[data.productId]){
retrieveObject[data.productId].count++;
}else{
retrieveObject[data.productId] = {
productPrice: data.productPrice,
count: 1
};
}
console.log(retrieveObject);
localStorage.setItem('Products', JSON.stringify(retrieveObject));
}
This creates a first entry in local storage that looks like this : {"productPrice":"78.34","count":1}, and then when adding others looks like this: {"productPrice":"78.34","count":1,"rJUg4uiGl":{"productPrice":"78.34","count":3}} and works perfectly fine. The issue is getting the first entry to b formatted properly. When I change the code in the first if statement like so:
var obj = [];
obj[data.productId] = {
productPrice: data.productPrice,
count: 1
}
I get an empty [] in local storage but when I console.log the obj it is in the proper format. [rJUg4uiGl: Object]. I have been stuck on this and haven't been able to get it working. Again, any help would be really appreciated.
Once you have your data structure in obj, I would suggest using a dictionary with product IDs as keys.
To add the order or whatever, where you have:
obj.push({"productPrice": data.productPrice, "productId": data.productId});
Use:
if (obj[data.productId]) { // if the entry exists,
// increment the count
obj[data.productId].count++;
} else { // if it doesn't,
// add a new entry with count = 1
obj[data.productId] = {
productPrice: data.productPrice,
count: 1
};
}
Here is a complete function, including localStorage handling:
function addToCart(productID, productPrice) {
// get the current cart, or an empty object if null
var cart = JSON.parse(localStorage.getItem("Products")) || {};
// update the cart by adding an entry or incrementing an existing one
if (cart[productId]) {
cart[productId].count++;
} else {
cart[productId] = {
productPrice, // shorthand for `productPrice: productPrice,`
count: 1
};
}
// put the result back in localStorage
localStorage.setItem("Products", JSON.stringify(cart));
}
The solution above is preferable because you can check for a productId without looping through the whole list. If you really want to keep your current data structure of an array of objects, you could update it like this:
var length = retrieveObject.length;
console.log(length);
for (var i = 0; i < length; i++) {
if (retrieveObject[i].productId == data.productId) {
retrieveObject[i].quantity++; // update the entry in the array
} else {
retrieveObject.push({
productPrice: data.productPrice,
productId: data.productId,
quantity: 1
});
}
}
Note that you shouldn't push a new entry into the array; just update the existing one.
Just use localstorage.getItem; it returns null if the key doesn't already exist.
Assuming you are using localStorage node package you could do
if (localStorage.getItem('Products') !== null) {
localStorage.setItem('Products', JSON.stringify(obj));
}
Here is your reference:
https://www.npmjs.com/package/localStorage
Regards
Update:
Searching within your objet is a different story... so you want to check if the Product id is there then you can search for it using lodash
var _ = require('lodash');
// the rest of your code to get the data.productId set
if (localStorage.getItem('Products') !== null) {
var arrayOfProducts = localStorage.getItem('Products');
var existingProducts = _.filter(arrayOfProducts, function (product) { return product.productId === data.productId });
if (existingProducts.length > 0) {
// product found, do your logic
}
}
Here's lodash info https://www.npmjs.com/package/lodash
The other option is using a dictionary and having the productId as key and then using Object.keys to search for it... I've offered an approach that does not change your json structure.

javascript: array with unknown length and unknown index names

I am making a program of a football league.
A example of a league:
team1
team2
team3
I want to save (increase) number of players for each team like
var teamArray = [];
teamArray[team1] = 1;
teamArray[team2] = 2;
and I am doing in the body of some functions like:
function 1(){}
function 2(){}
function .(){}
function .(){}
function .(){}
function n(){}
but this works only when i "teach" javscript that the array is an integer array... with somethin like
teamArray[team1] = 0;
teamArray[team1] = teamArray[team1] + 1;
but the problem is every time when i come to one of my functions, i have to set my array element to 0 and that makes the whole calculation wrong...
Could anyone give me a hint please?
My Idea was to was to set each array element to 0 from the beginning, but i dont know at the beginning of my game how many teams i will have today, that why i implemented the array like:
var teamArray = [];
Use a JavaScript object instead. Something like:
var teamObject = {
team1: 3,
team2: 5,
team3: 7,
};
Or, perhaps an array of objects:
var teamArray = [
{ name: 'team1', players: 3 },
{ name: 'team2', players: 5 },
{ name: 'team3', players: 7 }
];
The object is easier to access if all you want is to get or set the number of players:
teamObject.team1 += 1;
but an array is easier to loop through and can be ordered:
for (var i=0,j=teamArray.length; i<j; i++) {
console.log(teamArray[i].name + " has " + teamArray[i].players + " players");
}
You can increment the number of team members by testing the current number first, and if it does not exist, you initialise it with 0 on the fly. All that can be done in one expression with a logical OR (||):
teamArray[team1] = (teamArray[team1] || 0) + 1;
This will not destroy the previous value you had and work like a simple + 1 in that case.
You should define your teamArray as object, although it will work with array as well (since that is an object as well):
teamArray = {}
The name is then of course a bit confusing, but I'll stick with it.
Whenever you need to iterate over the teams you have collected, then you can use a for loop like this:
for (var team in teamArray) {
console.log(team, teamArray[team]);
}
thanks for all your help!
I did it like this now:
var listItems = $("#teamsDropdown li");
listItems.each(function(idx, li) {
var team = $(li).text();
TeamPlayerQuantities[team] = 0;
});
and increasing the qnty of players wiht functions like:
function1(team){
TeamPlayerQuantities[team] ++;
}

How to purge duplicate objects from MongoDB

I have an array inside an object in my database that accumulates duplicate objects over time (a drawback of working with the unreliable Instagram API). I'm attempting to routinely purge this array of duplicates and replace it with the cleaned up array. I'm having a difficult time understanding why the below code run on my node server does not work. The trimArray function works perfectly, but the 'photos' array within my MongoDB object is never updated.
// Takes in an array and outputs an array with only unique objects
function trimArray(bloatedArray) {
var seen = {};
var trimmedArray = [];
var len = bloatedArray.length;
var j = 0;
for(var i = 0; i < len; i++) {
var imageLink = bloatedArray[i].link;
var image = bloatedArray[i];
if(seen[imageLink] !== 1) {
seen[imageLink] = 1;
trimmedArray[j++] = image;
}
}
return trimmedArray;
}
Event.find( { $and: [{latitude: latitude}, {radius: distance}] },
function(err,event){
if (err) {
} else {
var array = event[0].photos;
Event.update( { $and: [{latitude: latitude}, {radius: distance}] },
{ 'photos': trimArray(array) }
);
}
}
);
I think update will simply update existing records, not remove them. It looks for items in the returned array and updates them accordingly. If you want to use your trimArray, you'll have to empty the collection and then reinsert the trimArray results (terrible idea).
Instead, you should set your collection up correctly to not store duplicates in the first place. You'll want to set up a unique index, and then you'll never have to purge.
See the docs for details.
db.things.ensureIndex({'photos.make_some_key' : 1}, {unique : true, dropDups : true})

Count how many identical elements in 2 arrays occur

I have a form and as a result of that form I have two arrays - one for personA's details and one for personB's details. One part of the form is a bunch of checkboxes of dates - the dates are a fixed price, but booking for two on the same date is a reduced price.
What I want to do is compare personA's array with personB's array and for any duplicates issue a reduced rate.
The rate will be calculated into two variables - total full price dates (in £s) and total reduced price dates (in £s).
Here is my code so far (this occurs on the checkboxes onclick):
function processDates(){
var contentsA, valsA = [], dates_A = document.forms['registerForm']['personADates[]'];
for(var iA=0,elmA;elmA = dates_A[iA];iA++) {
if(elmA.checked) {
valsA.push(elmA.value);
}
}
contentsA = valsA.join(', ');
var contentsB, valsB = [], dates_B = document.forms['registerForm']['personBDates[]'];
for(var iB=0,elmB;elmB = dates_B[iB];iB++) {
if(elmB.checked) {
valsB.push(elmB.value);
}
}
contentsB = valsB.join(', ');
}
With my own http://phrogz.net/JS/ArraySetMath.js you could do:
// If the original order of the elements is not important
var common = array1.intersect( array2 );
// If the original order of the elements is important
var common = array1.unsortedIntersect( array2 );
With the larger JS.Set you could do:
// If the original order of the elements is not important
var common = (new JS.SortedSet(array1)).intersect(new JS.SortedSet(array2));
// If the original order of the elements is important
var common = (new JS.Set(array1)).intersect(new JS.Set(array2));
It is not clear to me what the values in your arrays actually are; are these dates entered by the user in plain text? If so, you'll want to ensure that they are normalized so that they are comparable and guaranteed to match.
If these are more than simple comparable objects (e.g. instead of String or Date instances you are creating arrays complex Objects) then my library allows you to supply a comparison function so you can determine which are equal. See the library for more details on this.
Instead of using an array you could use an object (warning... untested code):
function processDates(){
var valsA = {}, dates_A = document.forms['registerForm']['personADates[]'];
for(var iA=0,elmA;elmA = dates_A[iA];iA++) {
if(elmA.checked) {
valsA[elmA.value] = 1; // Store values
}
}
var samedate = [];
var dates_B = document.forms['registerForm']['personBDates[]'];
for(var iB=0,elmB;elmB = dates_B[iB];iB++) {
if(elmB.checked) {
if (valsB[elmB.value])
{
// Here we found a date that's present in both
samedate.push(elmB.value);
}
}
}
// Here samedate is a list of all dates listed in both A and B
}
If functional javascript is an option:
_.sum = function(array) {
return _.reduce(array, function(memo, val) {
return memo + val;
}, 0);
};
var duplicates = _.intersect(valsA, valsB);
var fullPrice = _.sum(valsA.concat(valsB));
var reducedPrice = fullPrice - discountScalar * _.sum(duplicates);
Relies on underscore.js for easy cross browser implentation of functional methods. Most of these can be implemented with array.reduce & array.map on modern browsers.

Categories

Resources