Store a table row index as an array index - javascript

There a simple function:
selected_row = []; // global scope
function toggleRowNumber(rowIndex) {
if(selected_row[rowIndex]) selected_row.splice(rowIndex, 1);
else selected_row[rowIndex] = 1;
}
usage
toggleRowNumber(50000); // click the row - write the index
toggleRowNumber(50000); // click the row again - remove the inxed
alert(selected_row.length);
50001
OK
Delightful feature!
So is there a way to direct write|read an index without any searchin/looping? And without this huge feat as decribed above.
Thanks.

If I understoold correctly, you want to store and index where you can check/set whether an item is selected or not. If that is the case, you are looking for a "key - value" data structure. Then, why not use a map?
var selected_row = {};
function toggleRowNumber(rowIndex) {
if(selected_row[rowIndex]) selected_row[rowIndex] = 0; //or = undefined;
else selected_row[rowIndex] = 1;
}
That is better because hash map will save you time and space.
Space becuase you are not storing hundreds of 'undefined' values in a vector.
Time because, hash function used to access elements is pretended to hit the right position in many cases.

Related

How to create a function to count items from a set and store counts in an array parallel to one containing related items?

I am having trouble completing one of the last assignments in my semester-long high school-level programming class. I have been assigned to create a JavaScript program which counts the amount of time different ZIP codes appear in a set and output parallel arrays containing the zip codes and their counts. I am having difficulty getting the values to output. I believe that the respective zips and counts aren't being entered into their arrays at all.
I'm not looking for an original solution to the problem. I'd just like someone to tell me why my code isn't working, and possibly what I can change in my code specifically to fix it.
Usually I would never ask for help like this. I actually took the class last semester and now that I'm at the end of the year I have the option of completing it to earn college credit. I have never been the best at working with functions, and that remains true now. In the code below are all the moving parts I'm allowed to work with. I know it looks messy and rudimentary, but it's all I know. I'd appreciate it if any answers use only the sorts of things I used in my code. Another note, I am required to use functions for 'all identifiable processes', but I'm pretty sure my instructor only cares about the final product, so I'm not sure that the functions really matter, even if they could help.
var records = openZipCodeStudyRecordSet(),
uniqueZips = [],
zipCounts = [],
output = "";
function project62Part1() {
table = document.getElementById("outputTable");
function countZips(zip) {
var currentZip,
count;
while (records.readNextRecord()) {
currentZip = records.getSampleZipCode();
if (zip === currentZip) {
count++;
}
}
return count;
}
function processZip(zip) {
var currentZip;
while (records.readNextRecord()) {
currentZip = records.getSampleZipCode();
for (i = 0; i < uniqueZips.length; i++) {
if (uniqueZips[i] === "") {
uniqueZips.push(currentZip);
zipCounts[i] = countZips(currentZip);
break;
}
if (zip !== uniqueZip[i]) {
uniqueZips.push(currentZip);
zipCounts[i] = countZips(currentZip);
}
}
}
}
function createOutput(string) {
for (i = 0; i < uniqueZips.length; i++) {
string += "<tr><td>" + uniqueZips[i] + "</td><td>" + zipCounts[i] +
"</td></tr>";
}
return string;
}
processZip();
output = createOutput(output);
table.innerHTML = "<tr><td>Zip Code</td><td>Count</td></tr>" + output;
}
The output is supposed to be additional rows of zips and counts added to a table that is already set up on the page. There are no important technical errors in the code.
This is to be accomplished through the function processZip, which is meant to add respective zip and count into table rows. However, it appears as though the zip and count arrays its getting info from haven't had anything put into them by the other functions. I don't know if it is because of error in calling the functions, or what's in the functions themselves.
The HTML page this is connected to calls the function project62Part1().
That code is kind of all over the place but here's the logic you ideally want to follow:
Loop over each record in your table (outer loop) to get the zip code.
Declare an 'isFound' variable and set it to false
For each iteration of the outer loop, loop over your entire array of zip codes (inner loop).
3a. If you get a match, set isFound to true, increment your zipcode counter += 1 on the same index (since they're parallel arrays)
3b. If, at the end of your inner loop, isFound is still false, add the zipcode to your array of zip codes, and add a new array element to your zip code counters setting it to 1.
Since your zip code array and your zip code counter are parallel arrays to each other, when isFound is false, you are creating entries in both arrays, keeping them parallel to each other.
If, on 3a isFound is true, you are on the index of the zip code array that the zip code belongs to, so it should be the same index for your counter array.
In your current process zip function, the first condition will never be true, because starting out, your array size is 0 and after you start populating that array, you will never have an empty string (unless, of course, the zip code itself was an empty string)
The second if statement you have that checks if zip !== uniqueZip[i] - you are only checking that current value of uniqueZips and ignoring every other value in the array, so you will almost always have the second condition as true
I've been playing with the newer JavaScript language and syntax and your item was a good candidate for me to try out.
I did approach the code a little differently such as making the use of a Set for the unique values. Saves on code by not having to check and see if the value exists because the Set will never allow duplicate values in.
var uniqueZips = new Set();
const zipcodes = [21060, 22422, 25541, 43211, 21060, 22422, 22422, 43211, 43211, 43211];
function project62Part1() {
function processZipCodes() {
for(let index in zipcodes){
// We add every value because a SET will only allow you to add it once.
uniqueZips.add(zipcodes[index]);
}
}
// Structure our zipcode data information
function organizeZipCodeData() {
let response = {data:[]};
uniqueZips.forEach(function(zip) {
response.data.push( { 'zipcode':zip, 'appears': countZipAppearances(zip) })
});
return response;
}
function countZipAppearances(zip) {
// Default to zero even though you never expect an undefined
let count = 0;
zipcodes.forEach(function(zval) {
if (zip === zval) {
count++;
}
});
return count;
}
function showZipcodeInformation(data){
for (var index in data) {
if (data.hasOwnProperty(index)) {
var entry = [data[index]][0];
console.log(entry.zipcode, entry.appears);
}
}
}
// UI CONTENT: Construct the UI view from the data
function generateHtmlView(data){
let htmlview = "<table><tr><td>Zip Code</td><td>Count</td></tr>";
for (var index in data) {
if (data.hasOwnProperty(index)) {
var entry = [data[index]][0];
htmlview+="<tr><td>"+entry.zipcode+"</td><td>"+entry.appears+"</td></tr>";
}
}
htmlview += "</table>";
console.log(htmlview);
return htmlview;
}
// //////////////////////////////////////////////////////
// Call to gather the zipcodes
processZipCodes();
// Call to organize the zipcode data
let output = organizeZipCodeData();
// See what we have in the organized data
showZipcodeInformation(output.data);
// See what we have in the html content
generateHtmlView(output.data);
}
// Initiate the process
project62Part1();

Create a immutable copy of a property

I have a situation where I want to make a unchangeable copy of a property to restore state to its original... well state.
I have a array of group objects.
Inside each group i have and array of items.
When I make the copy bellow everything is fine.
I start by doing this.
componentDidMount(){
// originalGroups = Object.assign([], this.props.modalitygroups);
originalGroups = JSON.parse(JSON.stringify(this.props.modalitygroups));
},
I have tried both of the statements above, but have read that the current active one makes a true deep copy of a object. Needles to say it does copy it properly.
I then have THIS search feature to search for items in the groups and items.
_searchFilter:function(search_term){
this.setState({modalitygroups:originalGroups});
let tempGroups = Object.assign([], this.state.modalitygroups);
if(search_term !== ''){
for (let x = (tempGroups.length) - 1; x >= 0; x--)
{
console.log("originalGroups",x,originalGroups);
for (let i = (tempGroups[x].items.length) - 1; i >= 0; i--)
{
if(!tempGroups[x].items[i].description.toLowerCase().includes(search_term.toLowerCase())){
tempGroups[x].items.splice(i,1);
}
}
if(tempGroups[x].items.length === 0){
tempGroups.splice(x, 1);
}
}
this.setState({modalitygroups:tempGroups});
}
},
So I start of by restoring the original state to enable searching through everything. The search feature loops though each groups and within each group loop I loop through each item deleting items that dont contain the search phrase.
After looping through each item, if no item remain in the group, I remove that group from the group array aswell.
This works well first time arround.
But when I start searching for a new item, I find that the originalGroups has changed aswell. The previous deleted items has been removed from the unchangable copy aswell and I dont know why. Where and why does it change my safe copy?
Hope this makes sense.
So modality groups contains original groups? This is hard to follow... Instead of 'saving' the original groups, I'd leave this.props.modalitygroups alone and copy to a filteredGroups of the state. You can reload that from the props that you never change.
In your filter function when you do let tempGroups = Object.assign([], this.state.modalitygroups); that should probably be where you use json to create a deep copy. That is filling the new array with the same group references in the old array, so you are modifying the same group instance in the original.
_searchFilter:function(search_term){
// deep copy
let tempGroups = JSON.parse(JSON.stringify(this.props.modalitygroups));
if(search_term !== ''){
for (let x = (tempGroups.length) - 1; x >= 0; x--)
{
console.log("originalGroups",x,originalGroups);
for (let i = (tempGroups[x].items.length) - 1; i >= 0; i--)
{
if(!tempGroups[x].items[i].description.toLowerCase().includes(search_term.toLowerCase())){
tempGroups[x].items.splice(i,1);
}
}
if(tempGroups[x].items.length === 0){
tempGroups.splice(x, 1);
}
}
this.setState({modalitygroups:tempGroups});
}
},
const state = {
property1: 42
};
const originalGroups = Object.freeze(state);
originalGroups.property1 = 33;
// Throws an error in strict mode
console.log(originalGroups.property1);
// expected output: 42
Essentially ReactJS is still javascript afterall, so you can apply Object.freeze to save a copy of state

localStorage array is being overwritten after refresh

So my localStorage values in array are being overwritten after the refresh. While in session, I can change values on front end and array in localStorage constantly will be updated or if more inputs changed, then more values to array added. If for example I had 3 inputs changed and all their values was added to localStorage array in the session then after webpage refresh if I will edit one of the inputs again, all the arrays in localStorage will be deleted and overwritten by the new's session update of input. I'm trying to figure out this for a long time, but can't figure out how to make it work so that after the refresh all the input values would be stored in the old array and not overwritten.
var presetsArr = [];
if (!localStorage.getItem("presetsArr") || localStorage.getItem("presetsArr").length < 0) {
init();
} else {
initIfLocalStorage();
}
function initIfLocalStorage () {
presetsArr = JSON.parse(localStorage.getItem('presetsArr'));
for (var i = 0; i < presetsArr.length; i++) {
if (presetsArr[i].freq) {
osc.frequency.value = presetsArr[i].freq;
freqSlider.value = presetsArr[i].freq;
freqDisplay.innerHTML = freqSlider.value;
}
if (presetsArr[i].detune) {
osc.detune.value = presetsArr[i].detune;
detuneSlider.value = presetsArr[i].detune;
detuneDisplay.innerHTML = detuneSlider.value;
}
if (presetsArr[i].gain) {
volume.gain.value = presetsArr[i].gain;
}
}
freqSlider.addEventListener("click", function(e) {
osc.frequency.value = this.value;
freqDisplay.innerHTML = this.value;
bookmark["freq"] = osc.frequency.value;
presetsArr.push(bookmark);
presetsArr = localStorage.setItem("presetsArr", JSON.stringify(presetsArr)) || [];
})
detuneSlider.addEventListener("click", function(e) {
osc.detune.value = this.value;
detune.innerHTML = this.value;
bookmark["detune"] = osc.detune.value;
presetsArr.push(bookmark);
presetsArr = localStorage.setItem("presetsArr", JSON.stringify(presetsArr)) || [];
})
Here is what I mean: First session, I changed both frequency and detune values, they got stored in the array. http://imgur.com/0GIeQPj
Now after refresh in the second session, I changed the detune value again and the whole localStorage array got overwritten. Now frequency key is gone and only detune left. So after refresh next time I want to play my oscillator, I won't get any sound out of it, because frequency value in the array was removed.
http://imgur.com/crTywnN
For anyone running in the same kind of problem, here is the solution I came across.
So like Patrick Evans said, I made a mistake by assigning .setItem() to a variable, even though .setItem() doesn't return any value. So I just always create a new empty array when I click after the resfresh (in the new session). But that is not enough. Now I was running into a problem, where I was trying to push values into non-existing array and getting null error. I changed my click handler to:
presetsArr = JSON.parse(localStorage.getItem('presetsArr')) || [];
presetsArr.push(bookmark);
localStorage.setItem("presetsArr", JSON.stringify(presetsArr));
|| [] helped me to get rid of Null error. Even though I created en empty array at the top of my program, for some reason inside the click hander I couldn't push anything to it, so this little shortcut helped me to check if there is an array to push to and if there is not, then create one before pushing.
Now I can refresh the webpage and continue changing input values without overwriting and recreating localStorage array.

I am trying to stop my function from displaying the same object twice when clicking a button

I have for quite some time now been trying to figure out how I can stop my code to print the same quote twice.
Also, when every single object in the array has been printed out, I'd like for it to reset somehow. So that you can browse through the quotes once you've gone through all of them.
This is the essential parts of my code:
document.getElementById('loadQuote').addEventListener("click", printQuote, false);
The printQuote function simply contains information that's accessing information from my array:
var randomObjectNumber = getRandomQuote();
var html = "<p class='quote'>"
+ quotes[randomObjectNumber].quote +
"</p>";
document.getElementById('quote-box').innerHTML = html;
One random object is displayed each time you click the eventListener:
function getRandomQuote () {
var randomObjectNumber = Math.floor(Math.random() * quotes.length );
return randomObjectNumber;
}
I have some ideas on how to do this and I have tried them but without success. I tried giving each object a boolean property but I can't really seem to assign each property a boolean value without messing the printQuote function up.
I also tried assigning the object displayed to a different array but the same problem occurred there.
I feel like there is some concepts around the eventListener that I don't fully understand, because every time I try to manipulate a displayed object I just end up changing every single object.
This is what a typical object in the array looks like by the way:
{quote : "Darkness is merely the absence of light"}
(I also have other properties assigned to the object but i feel like presenting them would be redundant)
If someone could explain, or give me a hint, on how to solve this problem I've been struggling with for some time.
Some hints would be greatly appreciated!
Have a nice day.
Sebastian.
EDIT: All code: https://jsfiddle.net/fusqb7hz/
Basically what you need:
Create a separate array that will store all quotes that you've already used.
Remove quote from initial array.
Check if you still have quotes in initial array, if not, get them back from backup array.
The problem is that you call addEventListener twice:
//Let's developers create multiple eventListeners without being redundant.
function onClicking (printFunction) {
document.getElementById('loadQuote').addEventListener("click", printFunction, false);
}
onClicking(printColor);
onClicking(printQuote);
by calling onClicking twice you make the click happen twice, so addEventListener is added twice, meaning one click counts as two.
Change the above code for this:
//Let's developers create multiple eventListeners without being redundant.
document.getElementById('loadQuote').addEventListener("click", function(){
printColor();
printQuote();
});
Here is the jsfiddle:
https://jsfiddle.net/fusqb7hz/3/
I think the easiest approach is to shuffle your quote array and then go through them one by one. This gives you the next "random" as yet unseen quote. The only part I'm not keen on is this shuffler (a derivation of Fisher Yates) modifies the original quote array. You might not care about that though.
// --------------------------------
// A bunch of quotes
// --------------------------------
var quotes = [];
quotes.push({quote : "Darkness is merely the absence of light"});
quotes.push({quote : "quote 2"});
quotes.push({quote : "quote 3"});
quotes.push({quote : "quote 4"});
quotes.push({quote : "quote 5"});
// --------------------------------
// --------------------------------
// Your favorite array shuffle utility
// --------------------------------
var shuffle = function(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
};
// --------------------------------
// --------------------------------
// construct a function to get a random unseen quote until
// all quotes have been seen. Then reset...
// --------------------------------
var getQuote = (function(quotes, shuffle){
var current = 0;
var get = function(){
if ( !quotes || !quotes.length ) { return ""; }
if ( current >= quotes.length ){ current = 0; }
if ( current === 0 ){
console.log("randomizing quotes...");
shuffle(quotes);
}
return quotes[current++].quote;
};
return get;
})(quotes, shuffle);
// --------------------------------
var printQuote = function(){
document.getElementById('quote').innerText = getQuote();
};
document.getElementById('loadQuote').addEventListener("click", printQuote, false);
<div id="quote"></div>
<button id="loadQuote">get quote</button>

Javascript - storing the index of all array values in a variable

Say I have an array in JS: var fruits = [apple,orange,banana]
I want to store the index of each fruit in variables such that at any point in time, if I add more stuff to the array, I will still know that the index of apple is X. So in this case, 0 is apple, but if I add something to the beginning of that away, the index of apple changes.
The more verbose way I can think of is to loop through the array
for (var i=0;i<fruits.length;i++) {
switch(fruits[i]) {
case:"apple"
var indexApple = i;
break;
//etc
}
}
Another way I can think of is use the value of the arrays as the variable name.
for (var i=0;i<fruits.length;i++) {
//psedo code
var 'index' + fruits[i] = i;
}
So in the end I'd have var indexApple = 0, indexOrange = 1, etc. THe key to the second method is to be able to create a dynamic variable by concatenating the string 'index' and the value of the array to create that variable. Not sure how to do that.
Note: Ideally I want the variables that store the index to be dynamically generated. Such that I only I can modify/add to the fruits array, and a new variable will be generated to store the index.
it seems like ensuring your the value of the index is legitimate will be difficult. i would include jquery and use the inArray method which returns the index of the item in the array.
function showIndexes() {
var appleIndex = $.inArray(fruits, "Apple"); //returns 0
var guavaIndex = $.inArray(fruits, "Guava"); //returns -1
fruits.unshift("Guava");
appleIndex = $.inArray(fruits, "Apple"); //returns 1
guavaIndex = $.inArray(fruits, "Guava"); //returns 0
}
The simplest solution is simply to build an Object which gives you nearly O(1) lookup time, and will scale with your array:
function LinkFruits(fruits) {
FruitLookup = {}
fruits.forEach((fruit,ind) => FruitLookup[fruit] = ind)
}
Now you can simply "lookup" your index from the FruitLookup table when needed like:
console.log("The index of apple is",FruitLookup.apple,"and for orange is",FruitLookup.orange)
Now if you modify your array you simply need to run LinkFruits(fruits).
Technical Note: If you want to fully automate this process you can look into Array.observe() which is now deprecated. Or overload the push and pop methods of this array to trigger the update before falling back to the default prototype methods.

Categories