Trying to understand Javascript array - javascript

So I have a few arrays
var item = [{
name : "somename",
type1 : "wood",
location : "some location",
desc : "some description"
}, {
name : "somename",
type1 : "metal",
location : "somelocation",
desc : "some description"
}];
and
var shopState = 0;
var hasInv = [];
var pickedItem = [];
I assume I have 2 empty arrays with that last one. Later on I attempt to make use of these in a function.
function shop() {
for (var i = 0; i < item.length; i++) {
if (item[i].location == "some location") {
//get all items at some location
hasInv[i] = item[i];
}
}
if (shopState == 1) {
var d = 1;
for (var i = 1; i < hasInv.length; i++) {
if (hasInv[i].type1 == 'wood') {
//get all wood items at some location
pickedItem[d] = hasInv[i];
d++;
console.log(pickedItem);
}
}
}
}
That last bit with pickedItem returned undefined unless I declare pickedItem = []; in shopState when I thought I already declared it at the start of the file. It works when I do but I'm trying to understand why it does not if i don't.

A couple of questions: Is your conditional for shopState passing? I don't see where you increment shopState. Also is there a reason you are setting to indexes directly instead of using .push or .unshift? Maybe for time complexity concerns? I'm assuming the purpose of the function is to iterate through store locations to find matching locations and then find all items of a certain type at that location? Is that correct? If that is true here is the solution:
function shop() {
for (var i = 0; i < item.length; i++) {
if (item[i].location == "some location") {
//get all items at some location
hasInv.push(item[i]);
//You weren't increment shopState
shopState++;
}
}
if (shopState == 1) {
//conditional now passes
//there is no need to set a additional index variable.
for (var i = 0; i < hasInv.length; i++) {
if (hasInv[i].type1 == 'wood') {
//get all wood items at some location
pickedItem.push(hasInv[i]);
console.log(pickedItem);
}
}
}
}
shop()
Also note that your conditional makes it so you will only locate one item with the wood type. To change this so that your comment is true and you are collecting all items simply change your conditional to:
if(shopState >= 1)
As well you are only checking one location because you have combined the words some and location in the second object of your items array.

Related

Create new array by matching values passed in url using JavaScript

I am building a web application that is primarily using Tableau elements (filters, visualizations, etc.) and the problem I have run into is in passing a large amount (dynamic) of filtered parameters across web pages. I've been trying to work with the JavaScript below, but not having any luck.
function getFilterd()
{
var worksheets = vizFilter.getWorkbook().getActiveSheet().getWorksheets();
var prjArray = window.location.search.substring(1).split(',');
var newArray = [];
//Run through field/filter names
var displayFilters = function (filters) {
for (var i = 0; i < filters.length; i++) {
filterName = filters[i].getFieldName();
//If field/filter name == PRJECT then store selected values in an array
if (filterName == 'PRJECT') {
filterList = []
for (var z = 0; z < filters[i].getAppliedValues().length; z++) {
filterList[z] = filters[i].getAppliedValues()[z].value;
}
//Compare filterList values to prjArray and push to newArray if a match
for (var t = 0; t < filterList.length; t++) {
if (filterList[t].getAppliedValues()[t].value.substring(4) == prjArray) {
newArray.push(filterList[t]);
}
}
}
}
}
}
//Runs through each worksheet in active workbook (optional)
for (var worksheetIndex = 0; worksheetIndex < worksheets.length; worksheetIndex++){
worksheets[worksheetIndex].getFiltersAsync().then(displayFilters);
}
}
So I was finally able to figure this out. The logic below was incorrect as mentioned by Justin in his answer:
//Compare filterList values to prjArray and push to newArray if a match
for (var t = 0; t < filterList.length; t++) {
if (filterList[t].getAppliedValues()[t].value.substring(4) == prjArray) {
newArray.push(filterList[t]);
}
}
In addition, were some syntax errors in the if statement. The following is the revised statement that did return the desired array:
//Compare filterList values to prjArray and push to newArray if a match
newArray = []
for (var t = 0; t < filterList.length; t++){
if (prjArray.indexOf(filterList[t].substring(4)) != -1) {
newArray.push(filterList[t]);
};
}
When you do a split() on window.location.search.substring(1), you return an array. Here, you are comparing a substring against an array, and that is always going to return false.
if (filterList[t].getAppliedValues()[t].value.substring(4) == prjArray) {
newArray.push(filterList[t]);
}
Additionally, you are only putting values into filterList and trying to access them with getAppliedValues is not going to work.
You need to test if the substring is within the array. You can do this using includes() to determine if the array includes the value provided.
if (prjArray.includes(filterList[t].substring(4))) {
newArray.push(filterList[t]);
}
The includes() method is not completely supported by all browsers. If you need backward compatibility,you can do this using indexOf and test is it returns other than -1
if (prjArray.indexOf(filterList[t].substring(4)) !== -1) {
newArray.push(filterList[t]);
}

Save multiple entries to same post in local storarge

I'm trying to save a shopping cart to local storage but having trouble to save it as I the way I want it to be saved. For each added order with the same id, the amount should increase and not create another duplicate of the input. I've got this semi-working with the first item/order but when I order more items they lay in the first order. And when I put the first order in again, it puts itself at the back and increases the amount in a weird way. Thankful for any help as I tried to fix this a couple of days now and tried a lot of different stuff with different results.
From local storage:
Button with id 88 pressed 4 times:
[{"id":"88","amount":4}]
Button with id 79 pressed 4 times:
[{"id":"88","amount":4},{"id":"79","amount":5}
,{"id":"79","amount":4},{"id":"79","amount":3},{"id":"79","amount":2}]
Then I press the button with id 88 again ONE time:
[{"id":"88","amount":5},{"id":"79","amount":5},{"id":"79","amount":4},
{"id":"79","amount":3},{"id":"79","amount":2},{"id":"88","amount":5},
{"id":"88","amount":5},{"id":"88","amount":5},{"id":"88","amount":5}]
And here is my javascript:
$("#btnBuyMovie").on("click", function () {
var movieId = getParameterByName("productId");
var amount = 1;
if (localStorage.getItem("shoppingCart") !== null) {
shoppingCartFromLS = JSON.parse(localStorage.getItem("shoppingCart"));
var newShoppingCart = new ShoppingCart(movieId, amount);
for (var i = 0; i < shoppingCartFromLS.length; i++) {
if (movieId != shoppingCartFromLS[i].id) {
shoppingCartFromLS.push(newShoppingCart);
localStorage.setItem("shoppingCart", JSON.stringify(shoppingCartFromLS));
}
}
for (var i = 0; i < shoppingCartFromLS.length; i++) {
if (movieId == shoppingCartFromLS[i].id) {
shoppingCartFromLS[i].amount++;
}
}
localStorage.setItem("shoppingCart", JSON.stringify(shoppingCartFromLS));
} if (localStorage.getItem("shoppingCart") == null) {
var shoppingCartFromLS = [];
newShoppingCart = new ShoppingCart(movieId, amount);
shoppingCartFromLS.push(newShoppingCart);
localStorage.setItem("shoppingCart", JSON.stringify(shoppingCartFromLS));
}
Problem
Following for-loop has multiple problems
This line doesn't look correct.
Assuming you meant it to be this way, there is a semicolon at the end of it and it is pushing a shopping cart to the result of push function
if (movieId != shoppingCartFromLS[i].shoppingCartFromLS.push(newShoppingCart);
Assuming the above line is what you meant it to be, you are checking if every item is not the same item you are looking for.
So, if that item is not found on any iteration, you add that item again.
for (var i = 0; i < shoppingCartFromLS.length; i++) {
if (movieId != shoppingCartFromLS[i].shoppingCartFromLS.push(newShoppingCart);
localStorage.setItem("shoppingCart", JSON.stringify(shoppingCartFromLS)); //this will happen for every item except the item that matches
}
}
Finally, this for-loop isn't required
for (var i = 0; i < shoppingCartFromLS.length; i++) {
if (movieId == shoppingCartFromLS[i].id) {
shoppingCartFromLS[i].amount++;
}
}
Solution
You need to optimize your code this way
var isFound = shoppingCartFromLS.some( function( item ){
var isFound = item.id == movieId; //this line is updated
item.amount += isFound ? 1 : 0;
return isFound;
})
if (!isFound)
{
shoppingCartFromLS.push( { id : movieId, amount : 1 } )
}
localStorage.setItem("shoppingCart", JSON.stringify(shoppingCartFromLS));

Is there a way to pull all select menu’s selected index in my html to add values to different arrays of my choice. A lot of code for 1 select menu

The function finds which tv character the user compares to based on their answers to my questions. My code now is very inefficient for multiple select menus!!! Maybe an object that takes all selectmenus in html and allows me to assign array values based on the selected index of a selectmenu.
function onSelectMenuBlur() {
"use strict";
/*list of arrays that will be added to when the user selects an option in a selectmenu.*/
var rickArray = [];
var shaneArray = [];
var bobArray = [];
var carolArray = [];
var lArray = [];
var sm = document.getElementById("selectmenu");
.onchange function that determines what array will be added to depending on the option selected in the select menu. This function will add an array value of 1 once to an array. Seems like an inefficient way, especially with multiple selectmenus!
sm.onchange = function() {
if(sm.selectedIndex + 1 === 1) {
rickArray.push(1);
shaneArray.pop();
bobArray.pop();
carolArray.pop();
lArray.pop();
alert(rickArray.length);
}
else if(sm.selectedIndex + 1 === 2) {
shaneArray.push(1);
rickArray.pop();
bobArray.pop();
carolArray.pop();
lArray.pop();
alert(shaneArray.length);
}
else if(sm.selectedIndex + 1 === 3) {
bobArray.push(1);
rickArray.pop();
shaneArray.pop();
carolArray.pop();
lArray.pop();
alert(bobArray.length);
}
else if(sm.selectedIndex + 1 === 4) {
carolArray.push(1);
rickArray.pop();
shaneArray.pop();
bobArray.pop();
lArray.pop();
alert(carolArray.length);
}
else if(sm.selectedIndex + 1 === 5) {
lArray.push(1);
rickArray.pop();
shaneArray.pop();
bobArray.pop();
carolArray.pop();
alert(lArray.length);
}
else{}
};
.onblur purpose to find array with biggest length or value out of all selectmenus to determine which person associated with the array the user is like. Again seems like an inefficient way to handle!
sm.onblur = function() {
var rickL = rickArray.length;
var shaneL = shaneArray.length;
var bobL = bobArray.length;
var carolL = carolArray.length;
var lL = lArray.length;
// unfinished if else statement !!
if(rickL > shaneL && rickL > bobL && rickL > carolL && rickL > lL) {
alert("you are Rick Grimes");
}
else{
alert("you are someone else");
}
};
}
Use a 2-dimensional array instead of separate arrays for each character, and then use the selected index as an index into the array.
var characters = [[], [], [], [], []];
sm.onchange = function() {
for (var i = 0; i < characters.length; i++) {
if (i == this.selectedIndex) {
characters[i].push(1);
alert(characters[i].length);
} else {
characters[i].pop();
}
}
};
To get the character names in there, make it an array of objects.
characters = [
{ name: "Rick",
array: []
},
{ name: "Carol",
array: []
},
...
}
Then you would use characters[i].array.push(1). And then when you want to say which character they are, find the object with the longest array and then print its .name.

JS category conversion function

Group to Category Conversion
var Auto = ['new_auto', 'add_auto'];
//more category objects
var categories = [Auto, Fire, Health, Life, Bank];
function groupToCat(group) {
for (x = 1; x < categories.length; x++) {
for (i = 1; i < categories[x].length) {
if (group == categories[x][i]) {
return categories[x]
}
}
}
}
I'm trying to use a loop within a loop in combination with a multi-dimensional array to achieve a neat conversion function from a group (string new_auto) to a string equal to the name of the category containing it (array object Auto).
But as it is, I'm returning the category object, not its name. How can I do this?
Dynamic item "de-categorization" function
As suggested by Palmsey in the comments, this is the proper way of discovering an object's parent category through the combination of a loop-within-a-loop and a multidimensional array.
//Define Category Names and Children
var Auto = {
name: 'Auto',
items: ['new_auto', 'add_auto']
};
var Fire = {
name: 'Fire',
items: ['new_fire', 'add_fire']
};
var Health = {
name: 'Health',
items: ['health']
};
//Bring each category into a single array
var categories = [Auto, Fire, Health, Life, Bank];
//Because of the complimentary nature of loops and arrays, we can
//access each additional dimension of the array with an additional
//loop dimension.
function groupToCat(group) {
for (x = 0; x < categories.length; x++) {
for (i = 0; i < categories[x].items.length; i++) {
if (group == categories[x].items[i]) {
return (categories[x].name);
}
}
}
return ("No match found!");
}
I chose this method above the alternatives because it's dynamic. Simply by continuing the pattern, we can convert the values of items to the groups that they belong to, and vice-versa, with any level of group complexity.

json sibling data

(forgive me if I use slightly incorrect language - feel free to constructively correct as needed)
There are a couple posts about getting data from JSON data of siblings in the returned object, but I'm having trouble applying that information to my situation:
I have a bunch of objects that are getting returned as JSON from a REST call and for each object with a node of a certain key:value I need to extract the numeric value of a sibling node of a specific key. For example:
For the following list of objects, I need to add up the numbers in "file_size" for each object with matching "desc" and return that to matching input values on the page.
{"ResultSet":{
Result":[
{
"file_size":"722694",
"desc":"description1",
"format":"GIF"
},
{
"file_size":"19754932",
"desc":"description1",
"format":"JPEG"
},
{
"file_size":"778174",
"desc":"description2",
"format":"GIF"
},
{
"file_size":"244569996",
"desc":"description1",
"format":"PNG"
},
{
"file_size":"466918",
"desc":"description2",
"format":"TIFF"
}
]
}}
You can use the following function:
function findSum(description, array) {
var i = 0;
var sum = 0;
for(i = 0; i < array.length; i++) {
if(array[i]["desc"] == description && array[i].hasOwnProperty("file_size")) {
sum += parseInt(array[i]["file_size"], 10);
}
}
alert(sum);
}
And call it like this:
findSum("description1", ResultSet.Result);
To display an alert with the summation of all "description1" file sizes.
A working JSFiddle is here: http://jsfiddle.net/Q9n2U/.
In response to your updates and comments, here is some new code that creates some divs with the summations for all descriptions. I took out the hasOwnProperty code because you changed your data set, but note that if you have objects in the data array without the file_size property, you must use hasOwnProperty to check for it. You should be able to adjust this for your jQuery .each fairly easily.
var data = {};
var array = ResultSet.Result;
var i = 0;
var currentDesc, currentSize;
var sizeDiv;
var sumItem;
//Sum the sizes for each description
for(i = 0; i < array.length; i++) {
currentDesc = array[i]["desc"];
currentSize = parseInt(array[i]["file_size"], 10);
data[currentDesc] =
typeof data[currentDesc] === "undefined"
? currentSize
: data[currentDesc] + currentSize;
}
//Print the summations to divs on the page
for(sumItem in data) {
if(data.hasOwnProperty(sumItem)) {
sizeDiv = document.createElement("div");
sizeDiv.innerHTML = sumItem + ": " + data[sumItem].toString();
document.body.appendChild(sizeDiv);
}
}
A working JSFiddle is here: http://jsfiddle.net/DxCLu/.
That's an array embedded in an object, so
data.ResultSet.Result[2].file_size
would give you 778174
var sum = {}, result = ResultSet.Result
// Initialize Sum Storage
for(var i = 0; i < result.length; i++) {
sum[result[i].desc] = 0;
}
// Sum the matching file size
for(var i = 0; i < result.length; i++) {
sum[result[i].desc] += parseInt(result[i]["file_size"]
}
After executing above code, you will have a JSON named sum like this
sum = {
"description1": 20477629,
"description2": 1246092
};
An iterate like below should do the job,
var result = data.ResultSet.Result;
var stat = {};
for (var i = 0; i < result.length; i++) {
if (stat.hasOwnProperty(result[i].cat_desc)) {
if (result[i].hasOwnProperty('file_size')) {
stat[result[i].cat_desc] += parseInt(result[i].file_size, 10);
}
} else {
stat[result[i].cat_desc] = parseInt(result[i].file_size, 10);
}
}
DEMO: http://jsfiddle.net/HtrLu/1/

Categories