i wanna generate a 3x3 field. I want to do this with JS, it shall be a web application.
All fields shall inital with false. But it seems so that my code is not working correctly, but i don't find my fault. The goal is, that every spacesector is accessible.
Thats my idea:
// define size
var esize = generateSpace(3);
}
space[i] = false is replacing the array with a single boolean value false, not filling in all the entries in array you just created. You need another loop to initialize all the elements of the array.
function generateSpace(x) {
var space = [];
for (var i = 0; i < x; i++) {
space[i] = [];
for (var j = 0; j < x; j++) {
space[i][j] = false;
}
}
return space;
}
Also, your for() loop condition was wrong, as you weren't initializing the last element of space. It should have been i < space.length.
And when it's done, it needs to return the array that it created.
Since I got somewhat bored and felt like messing around, you can also initialize your dataset as shown below:
function generateSpace(x) {
return Array.apply(null, Array(x)).map(function() {
return Array.apply(null, Array(x)).map(function() {
return false;
});
});
}
The other functions work equally well, but here's a fairly simply looking one using ES6 that works for any square grid:
function generateSpace(x) {
return Array(x).fill(Array(x).fill(false));
}
Related
The process: In the game I'm making, there's a for loop that's supposed to save a value in an array. That value changes with each iteration. The problem: when the loop is done running, every element of the array is identical, all showing the most recent value.
I know this issue is common, and I've made so many different tweaks and attempts at solving it over the past 2 days.
0) I tried separating things into separate functions as much as possible.
1) I tried defining my loop counters with "let" so they would have a local scope.
2) I tried wrapping my assignment in a self-executing function so it would happen immediately, preserving the value of currentlyOn before the next loop iteration changes it. My counter is the variable c.
(function(c2, currentlyOn2) {
onAtSameTime[c2] = currentlyOn2;
return 0;
})(c, currentlyOn);
3) I tried attempt #2 with the added feature of returning a function, which still didn't save the value of currentlyOn. This option isn't a good one for me anyway, because the whole point is that I'm doing some computations ahead of time so my game will have a quick animation loop.
onAtSameTime[c] = (function(currentlyOn2) {
return function() {
return currentlyOn2;
};
})(currentlyOn);
I'm tired of beating my head against this wall. Can anyone explain what I'm doing wrong?
For more details, check out the jsfiddle I made. The problem area is at line 59, using a simple assignment:
onAtSameTime[c] = currentlyOn;
onAtSameTime[c] = currentlyOn; sets onAtSameTime[c] equal to the reference of currentlyOn, since currentlyOn is an array, not a primitive value. That reference gets updated with each iteration. You could work around that by creating a copy of the array before adding it to the onAtSameTime array. Something like onAtSameTime[c] = [].concat(currentlyOn); would do the trick.
See this fork of your JSFiddle: https://jsfiddle.net/L2by787y/
You could make a copy from currentlyOn for assigning to onAtSameTime[c]. This keeps the values, but does not keep the reference to the same array.
onAtSameTime[c] = currentlyOn.slice(); // use copy
"use strict";
function log(text) {
document.getElementById("logbox").innerHTML += JSON.stringify(text) + "<br>";
return 0;
}
function whichSwitchesAreOn() {
var currentlyOn = [],
flickedSet,
flickedOne,
turningOnCheck;
for (var c = 0; c < switchesToggled.length; c++) {
flickedSet = switchesToggled[c];
for (var d = 0; d < flickedSet.length; d++) {
flickedOne = flickedSet[d];
turningOnCheck = currentlyOn.indexOf(flickedOne);
if (turningOnCheck == -1) {
currentlyOn.push(flickedOne);
} else {
currentlyOn.splice(turningOnCheck, 1);
}
}
log("currentlyOn: " + currentlyOn);
onAtSameTime[c] = currentlyOn.slice(); // use copy
}
return 0;
}
var switchesToggled = [[0], [1, 2], [0], [2], []],
onAtSameTime = [];
whichSwitchesAreOn();
log(onAtSameTime);
<div id="logbox"></div>
You say you have tried let?
Did you have let currentlyOn = [] inside of the for loop?
for(var c = 0; c < switchesToggled.length; c++) {
let currentlyOn = [];
console.log(previousCompetitors);
console.log(competitors);
if(data.isVisible) {
var moveIndexTo = [];
for(var q=0; q<competitors.length;q++) {
moveIndexTo.push(-1);
}
for(var i = 0; i<competitors.length; i++) {
for(var j = 0; j<previousCompetitors.length; j++) {
console.log(competitors[i].name);
console.log(previousCompetitors[j].name);
if(competitors[i].name === previousCompetitors[j].name) {
moveIndexTo[j]= i;
break;
}
}
}
console.log(moveIndexTo);
}
I'm slowly going insane trying to figure out what is happening here. I have an array of competitor data that updates in order. They are both arrays and I want to track the changes from the previous ordering.
I console.log the data and can see that the data order has been changed yet every single time the moveIndexTo array ends up being [0,1,2,3,4,5] implying that previousCompetitors an Competitors have equal order. How can they be changed between when I console.log them at the top of the code block to when I perform the string comparison?
Competitors and previousCompetitors take roughly the form
[{name:'name1'},{name:'name2'},{name:'name3'},{name:'name4'},{name:'name5'},{name:'name6'}]
with a lot more going on in each object. So If that was previousCompetitors then competitors would be something like
[{name:'name6'},{name:'name2'},{name:'name3'},{name:'name4'},{name:'name5'},{name:'name1'}].
Note the switch of name1 and name6. So I would expect moveIndexTo to be [5,1,2,3,4,0].
Just try this : moveIndexTo[i] = j;
fiddle at : https://jsfiddle.net/c9mbbpjj/
I am trying to make two arrays. the unique array can get the elements (no repeats) from the text array, and the counter one can count the frequency of each elements. but something is wrong with the counter one.
var unique_array=new Array();
var counter_array=new Array();
var unique=true;
for (i=0;i<text_array.length;i++){
if (unique_array.length==0){
unique_array.push(text_array[0]);
counter_array.push(1);
}
else if(unique_array.length>0&&unique_array.length<=text_array.length){
for (j=0; j<unique_array.length;j++){
if (text_array[i]==unique_array[j]){
counter_array[j]=counter_array[j]+1;// something wrong with the
alert(counter_array[j]);
var unique=false;
}
}
if (unique==true){
unique_array.push(text_array[i]);
counter_array.push[1];
}
unique=true;
}
You could also simplify the code down using a hashmap and some ES5 higher-order functions:
var text_array = ["a1","a1","a2","a3","a2","a4","a1","a5"];
var counts = {};
text_array.forEach(function(el) {
counts[el] = counts.hasOwnProperty(el) ? counts[el]+1 : 1;
});
var unique_array = Object.keys(counts);
var counter_array=unique_array.map(function(key) { return counts[key]; })
You can do this much more simply using an object. Let the values be the keys of an object, then just increment the count of each property as you go. At the end, you can get an array of the unique keys and their values:
var text_array = ['foo','bar','foo','fum','fum','foo'];
var i = text_array.length;
var obj = {};
while (i--) {
if (obj.hasOwnProperty(text_array[i])) {
obj[text_array[i]]++;
} else {
obj[text_array[i]] = 1;
}
}
console.log('Unique values: ' + Object.keys(obj)); // Unique values: foo,fum,bar
console.log('Value counts: ' + Object.keys(obj).map(function(v){return obj[v]})); // Value counts: 3,2,1
Note that the sorting of counts in the output is purely coincidental.
As Jasvir posted, you can make it pretty concise:
var obj = {};
text_array.forEach(function(v) {
obj.hasOwnProperty(v)? ++obj[v] : obj[v] = 1;
});
But the first example is a bit easier to digest.
I think the approach is what's making it difficult. A hash table / associative array would be much easier to work with.
With a hash table (an object {} in JS), you can store each word in a key and increment the value of the key when you encounter the word again. Then, at the end, just go through the hash table and gather up all the keys which have small values. Those are your unique words.
function get_unique_words(text_array) {
var hash_table, i, unique_words, keys;
hash_table = {};
for(i = 0; i < text_array.length; i++) {
if(hash_table[text_array[i]] === undefined) {
hash_table[text_array[i]] = 1;
} else {
hash_table[text_array[i]]++;
}
}
// go through the hash table and get all the unique words
unique_words = [];
keys = Object.keys(hash_table);
for(i = 0; i < keys.length; i++) {
if(hash_table[keys[i]] === 1) {
unique_words.push(keys[i]);
}
}
return unique_words.sort();
}
console.log(get_unique_words(
['blah', 'blah', 'blah', 'goose', 'duck',
'mountain', 'rock', 'paper', 'rock', 'scissors']
));
Some issues and suggestions :
Don't use var twice for the same variable.
Browsers deal with it ok, but for clarity you should only be declaring your variables once.
Always localize your loop counters - forgetting a var before your i and j will cause them to become global variables.
This is relevant when you have a page with lots of code - all global variables will show up in the debugger's watch list at all times, making it harder to debug your code.)
Use the array literal notation [] instead of the function form Array.
The function form is longer and it's easier to forget the new. It's also easier to read (IMO).
Use more whitespace (it won't bite), such as before and after an equals sign:
var x = 1;
// vs.
var x=1;
It makes the code easier to read and most people don't overdo it.
Indent your code when it's inside a block (e.g. function, if, else, while, for, etc.).
This makes it easier to read the control flow of the code and will help prevent bugs.
Use three equals signs (===) unless you are using loose equality on purpose.
This will help someone looking at your code later (probably yourself) understand better what the test is supposed to be testing.
Is there a good way to add a certain value to each element in an array in javascript? Essentially, this should be a better way of writing the following:
a = [1,2,3,4];
for (i = 0; i < a.length; i++) {
a[i] += 7;
}
Maybe using map (but not necessarily)?
Edit:
Or a more interesting example:
a = [{'x':1},{'x':2},{'x':3},{'x':4}];
for (i = 0; i < a.length; i++) {
a[i].x += 7;
}
You can use map to do it:
a = a.map(function(entry) {
return entry + 7;
});
I'm not seeing how it's "better" to create a new array rather than update the one you have.
You can also use forEach:
a.forEach(function(entry, index) {
a[index] += 7;
});
It's still a bunch of function calls (but that's not a problem), but you have the advantage (over a for loop) of not having to declare the indexing variable, and you're modifying the existing array rather than replacing it.
Edit: Your "most interesting" example says even more that map is not really the best choice.
a.forEach(function(entry) {
entry.x += 7;
});
Yes, you can use .map but it will not modify the array in-place, so you must assign the result to a:
a = a.map(function(x) { return x+7 });
I have a JSON response like this:
var errorLog = "[[\"comp\",\"Please add company name!\"],
[\"zip\",\"Please add zip code!\"],
...
Which I'm deserializing like this:
var log = jQuery.parseJSON(errorLog);
Now I can access elements like this:
log[1][1] > "Please add company name"
Question:
If I have the first value comp, is there a way to directly get the 2nd value by doing:
log[comp][1]
without looping through the whole array.
Thanks for help!
No. Unless the 'value' of the first array (maybe I should say, the first dimension, or the first row), is also it's key. That is, unless it is something like this:
log = {
'comp': 'Please add a company name'
.
.
.
}
Now, log['comp'] or log.comp is legal.
There are two was to do this, but neither avoids a loop. The first is to loop through the array each time you access the items:
var val = '';
for (var i = 0; i < errorLog.length; i++) {
if (errorLog[i][0] === "comp") {
val = errorLog[i][1];
break;
}
}
The other would be to work your array into an object and access it with object notation.
var errors = {};
for (var i = 0; i < errorLog.length; i++) {
errors[errorLog[i][0]] = errorLog[i][1];
}
You could then access the relevant value with errors.comp.
If you're only looking once, the first option is probably better. If you may look more than once, it's probably best to use the second system since (a) you only need to do the loop once, which is more efficient, (b) you don't repeat yourself with the looping code, (c) it's immediately obvious what you're trying to do.
No matter what you are going to loop through the array somehow even it is obscured for you a bit by tools like jQuery.
You could create an object from the array as has been suggested like this:
var objLookup = function(arr, search) {
var o = {}, i, l, first, second;
for (i=0, l=arr.length; i<l; i++) {
first = arr[i][0]; // These variables are for convenience and readability.
second = arr[i][1]; // The function could be rewritten without them.
o[first] = second;
}
return o[search];
}
But the faster solution would be to just loop through the array and return the value as soon as it is found:
var indexLookup = function(arr, search){
var index = -1, i, l;
for (i = 0, l = arr.length; i<l; i++) {
if (arr[i][0] === search) return arr[i][1];
}
return undefined;
}
You could then just use these functions like this in your code so that you don't have to have the looping in the middle of all your code:
var log = [
["comp","Please add company name!"],
["zip","Please add zip code!"]
];
objLookup(log, "zip"); // Please add zip code!
indexLookup(log, "comp"); // Please add company name!
Here is a jsfiddle that shows these in use.
Have you looked at jQuery's grep or inArray method?
See this discussion
Are there any jquery features to query multi-dimensional arrays in a similar fashion to the DOM?