How to prevent rewrite data in array while looping - javascript

What I like is an Array like this
myArray = [
[{"value":1},{"value":2},{"value":3}]
[{"value":2},{"value":4},{"value":6}]
]
I try to use two loops to build it. The outer loop shout build the two "outer" Elements in Array, the inner loop shout build the 3 inner objects.
http://jsfiddle.net/xtrem1234/xx06zt5s/
var dataset = [];
var categories = ["Category_1", "Category_2"];
var myArray = [];
categories.forEach(function (category, index) {
for (var n = 1; n < 4; n++) {
var d;
d = {};
d.value = (index+1) * n;
console.log("index: " + index);
console.log("n: " + n);
console.log("d.value: " + d.value);
dataset[n] = d;
}
myArray.push(dataset);
});
console.log(JSON.stringify(myArray));

The issue is, your array dataset is a global array. Define it inside forEach loop.
Code
var categories = ["Category_1", "Category_2"];
var myArray = [];
categories.forEach(function(category, index) {
var dataset = [];
for (var n = 1; n < 4; n++) {
var d;
d = {};
d.value = (index + 1) * n;
dataset[n] = d;
}
myArray.push(dataset);
});
console.log(JSON.stringify(myArray));

A: you need to reinitialize the dataset array each time the forEach loop runs
B: you can just push() the info to the dataset array, the same way you do for myArray
var categories = ["Category_1", "Category_2"];
var myArray = [];
categories.forEach(function (category, index) {
var dataset = [];
for (var n = 1; n < 4; n++) {
dataset.push({'value': (index+1) * n});
}
myArray.push(dataset);
});
console.log(JSON.stringify(myArray));

Related

Getting undefined error at JavaScript array quiz

I am trying to make a simple multiple choice-like quiz using data from an array, but I am getting an error: TypeError: Cannot read property '0' of undefined.
The possible choices should be 4, with the correct answer being the first choice. I have tried searching online for solutions, but I do not know what is causing the error and how to fix it:
var masterlist = [
["Indonesia", "Jakarta"],
["Malaysia", "Kuala Lumpur"],
["Philippines", "Manila"],
["Singapore", "Singapore"],
["Thailand", "Bangkok"],
["Vietnam", "Hanoi"]
];
function randomNoRepeats(array) {
var copy = array.slice(0);
return function() {
if (copy.length < 1) {
copy = array.slice(0);
}
var index = Math.floor(Math.random() * copy.length);
var item = copy[index];
copy.splice(index, 1);
return item;
};
}
var chooser = randomNoRepeats(masterlist); //randomize choices
//console.log(chooser());
var quizArea = document.getElementById("test-area");
var a = []; // new empty array to store randomized items
var c = []; // new empty array to store randomized items (copy)
var b;
var correctAnswer;
for (var i = 0; i < masterlist.length; i++) {
b = chooser();
a.push(b);
}
c = a;
//console.log("a", a, a.length); // ERROR here; expected an array length of 6
for (var i = 0; i < masterlist.length; i++) {
correctAnswer = c[i];
var index = a.indexOf(correctAnswer); // remove correct answer from list of other/wrong choices
a.splice(index, 1);
var otherChoices = a.slice(0, 3); // choose only 3 wrong/other choices
var question = document.createElement("p");
question.innerHTML = "What is the capital of " + correctAnswer[0] + "?"; // ERROR
var answers = document.createElement("p");
answers.innerHTML = correctAnswer[1] + ", " + otherChoices[0][1] + ", " + otherChoices[1][1] + ", " + otherChoices[2][1]; // place correct answer at index 0; TypeError: Cannot read property '0' of undefined
quizArea.appendChild(question);
quizArea.appendChild(answers);
}
<div id="test-area"></div>
The issue comes from the statement c = a;. It does not copy the array. Both c and a reference the same array object.
This means that the line a.splice(index, 1) changes a AND c in place.
One solution here is to use a real copy of a in your last for loop.
for (var i = 0; i < masterlist.length; i++) {
c = a.slice(0); // or c = [...a];
// use `c` here
}
var masterlist = [
["Indonesia", "Jakarta"],
["Malaysia", "Kuala Lumpur"],
["Philippines", "Manila"],
["Singapore", "Singapore"],
["Thailand", "Bangkok"],
["Vietnam", "Hanoi"]
];
function randomNoRepeats(array) {
var copy = array.slice(0);
return function() {
if (copy.length < 1) {
copy = array.slice(0);
}
var index = Math.floor(Math.random() * copy.length);
var item = copy[index];
copy.splice(index, 1);
return item;
};
}
var chooser = randomNoRepeats(masterlist); //randomize choices
//console.log(chooser());
var quizArea = document.getElementById("test-area");
var a = []; // new empty array to store randomized items
var c;
var b;
var correctAnswer;
for (var i = 0; i < masterlist.length; i++) {
b = chooser();
a.push(b);
}
//console.log("a", a, a.length); // ERROR here; expected an array length of 6
for (var i = 0; i < masterlist.length; i++) {
c = a.slice(0);
correctAnswer = c[i];
var index = c.indexOf(correctAnswer); // remove correct answer from list of other/wrong choices
c.splice(index, 1);
var otherChoices = c.slice(0, 3); // choose only 3 wrong/other choices
var question = document.createElement("p");
question.innerHTML = "What is the capital of " + correctAnswer[0] + "?"; // ERROR
var answers = document.createElement("p");
answers.innerHTML = correctAnswer[1] + ", " + otherChoices[0][1] + ", " + otherChoices[1][1] + ", " + otherChoices[2][1]; // place correct answer at index 0; TypeError: Cannot read property '0' of undefined
quizArea.appendChild(question);
quizArea.appendChild(answers);
}
<div id="test-area"></div>

shuffle two consecutive blocks of data

I have data file (php) with 24 blocks of data, structured as below.
//ts1
$P[] = [0];
$S[] = [[1,95.8172406762736],[2,104.97526726371],[3,112.03839938973],[4,101.70457396977],];
$F[] = [];
$FB[] = [];
//ts2
$P[] = [0];
$S[] = [[1,103.190939795922],[2,105.297198378469],[3,105.829786652111]];
$F[] = [];
$FB[] = [];
//ts3
$P[] = [0];
$S[] = [[1,107.285278217373],[2,103.557795069809],[3,105.686758569246],[4,103.748341353355]];
$F[] = [];
$FB[] = [];
I need to shuffle the first 12 blocks and then shuffle block 13-24. The code I have does not appear to work as it still shuffles all 24 blocks at once. I'm not sure how it should be written otherwise..
// DATA INITIALISATION
// - Reads all data sets from server
// - Generates list of objects
// - Randomises list of objects
function DataInit1()
{
SeriesList = [];
CurrentGraph.Series = 0;
// load all the data sets from server
$.getJSON("datademo.php",
function(Data1)
{
for(var i=0; i<Data1.length; i+=4)
{
var P = Data1[i+0];
var S = Data1[i+1];
var F = Data1[i+2];
var FB = Data1[i+3];
var NewSeries = new SeriesClass(P,S,F,FB);
NewSeries.SeriesNumber = (i/4)+1;
SeriesList.push(NewSeries);
}
}
);
// shuffle each of the series lists to a random order
s1 = SeriesList.length/2;
s2 = SeriesList.length;
for(var i=0; i<s1; i++)
{
var j = Math.floor(Math.random() * (i+1));
var x = SeriesList[i];
SeriesList[i] = SeriesList[j];
SeriesList[j] = x;
}
for(var i=s1; i<s2; i++)
{
var j = Math.floor(Math.random() * (i+1));
var x = SeriesList[i];
SeriesList[i] = SeriesList[j];
SeriesList[j] = x;
}
}
edit: I've changed it now to the following (not pretty but I don't have time to tidy it). Now it randomizes series 1-12, but series 13-24 is now not randomized. I don't code that often and I can't see why it would work in the first bit but not the second one.
// shuffle the series list to a random order
for(var i=SeriesList.length-13; i>0; i--)
{
var j = Math.floor(Math.random() * (i+1));
var x = SeriesList[i];
SeriesList[i] = SeriesList[j];
SeriesList[j] = x;
}
for(var i={from: 12, to: 23}; i>0; i--)
{
var j = Math.floor(Math.random() * (i+1));
var x = SeriesList[i];
SeriesList[i] = SeriesList[j];
SeriesList[j] = x;
}
I think the easiest way is to break it into two arrays, shuffle them separately, then push them back together. I've used the shuffle method from this question: How can I shuffle an array?, and the method of joining arrays from How to extend an existing JavaScript array with another array, without creating a new array?
See the fiddle at https://jsfiddle.net/u25ta64x/1/
var SeriesList = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26];
var firstHalf = SeriesList.slice(0,13);
var secondHalf = SeriesList.slice(13,26);
function shuffle(a) {
var j, x, i;
for (i = a.length; i; i--) {
j = Math.floor(Math.random() * i);
x = a[i - 1];
a[i - 1] = a[j];
a[j] = x;
}
}
shuffle(firstHalf);
shuffle(secondHalf)
var shuffledList = firstHalf;
Array.prototype.push.apply(shuffledList, secondHalf);
console.log(shuffledList);

add elements of two arrays - the best way

var a = "1:2:3:4";
var b = "0:1:5:2";
I want at the end:
var c = "1:3:8:6";
meaning, the numbers are summed by column.
my solution is:
var i, k;
var a_arr = a.split(':');
var b_arr = b.split(':');
for (i=0;i<a_arr.length;i++){
and here again another loop over b_arr
}
eeh ok, I dont have solution.. what is the cutest way to do this?
You could just map it and return the added values ?
var a = "1:2:3:4";
var b = "0:1:5:2";
var c = a.split(':').map(function(x, i) {
return (+x) + (+b.split(':')[i]);
}).join(':');
document.body.innerHTML = '<pre>' + c + '</pre>';
or splitting outside the map
var c = (function(y) {
return a.split(':').map(function(x, i) {
return (+x) + (+y[i]);
}).join(':')
})(b.split(':'));
Building on my comment, you can use i to index both the arrays:
var i, k;
var a_arr = a.split(':');
var b_arr = b.split(':');
var c_arr = [];
for (i=0;i<a_arr.length;i++){
c_arr.push(parseInt(a_arr[i], 10) + parseInt(b_arr[i], 10));
}
//And use join to get the final result
var c = c_arr.join(":");
You can use index i to add the simply use join()
var a = "1:2:3:4";
var b = "0:1:5:2";
var c = [];
var i, k;
var a_arr = a.split(':');
var b_arr = b.split(':');
for (i=0;i<a_arr.length;i++){
c[i] = parseInt(a_arr[i], 10) + parseInt(b_arr[i], 10); //Add using index
}
console.log(c.join(':')); //Use Join
http://jsfiddle.net/fLavfcjz/1/
Use .map() and don't forget parseInt() otherwise the numbers will considered as strings.
var a = "1:2:3:4";
var b = "0:1:5:2";
var arrayA = a.split(':');
var arrayB = b.split(':');
var combinedArr = arrayA.map(function (v, i) {
return parseInt(v,10) + parseInt(arrayB[i],10); // or return (+v) + (+arrayB[i]);
});
console.log(combinedArr.join(':')); //1:3:8:6
Try this
var a = "1:2:3:4";
var b = "0:1:5:2";
var a_arr = a.split(':');
var b_arr = b.split(':');
var c_arr = [];
for (i in a_arr) {
var to_add = 0;
if (b_arr[i] != undefined) to_add = b_arr[i];
c_arr[i] = a_arr[i] + to_add;
}
You don't need a second loop. The resulting array of the following snippet will have the length of the shorter input array.
var a = '1:2:3:4'
var b = '0:1:5:2'
var aArray = a.split(':')
var bArray = b.split(':')
var result = []
for (
var i = 0, aLength = aArray.length, bLength = bArray.length;
i < aLength && i < bLength;
i++
) {
result.push(Number(a[i]) + Number(b[i]))
}
result = result.join(':')
console.log(result)

split and group array javascript / jquery

I have
range = [a,3,b,2,c,1,d,2,e,3,f,3]
and need to group a,b,c,d,e,f into 3 same sized groups depending on their values.
Correct result would be:
group1 = [a]
group2 = [b,c]
group3 = [d,e,f]
Update: Pattern -> only group3 can be bigger then 1/3 of total groups. I have so far this:
var range = [3,2,1,2,3,3]
var total = 14;
var group_size = total / 3;
var values = [0];
var groupnr = 0;
range = range.reverse();
while( range.length ) {
var curvalue = range.pop();
if( values[groupnr] + curvalue > group_size && groupnr < 2 ) {
groupnr++;
values[groupnr] = 0;
}
values[groupnr] += curvalue;
}
log(values);
Something like
var range = ['a',3,'b',2,'c',1,'d',2,'e',3,'f',3];
var obj = {};
range.map(function(el, i) {
if (i%2) {
var k = 'group'+el;
obj[k] = obj[k] || [];
obj[k].push(range[i-1]);
}
});
gives you
{
"group1" : ["c"]
"group2" : ["b","d"],
"group3" : ["a","e","f"],
}
FIDDLE
That's about the only thing that would make sense ?
Here's at least one possibility:
var equalSplit = (function() {
var sum = function(list) {return list.reduce(function(a, b) {
return a + b;
}, 0);};
var evens = function(list) {
return list.filter(function(item, index) {return !(index % 2);})
};
var odds = function(list) {
return list.filter(function(item, index) {return !!(index % 2);})
};
var split = function(values, count) {
var mean = sum(values) / values.length;
var groups = [], index = 0, total, groupStart;
for (var i = 0; i < count - 1; i++) {
total = 0; groupStart = index;
while (index < values.length && total < mean) {
total += values[index++];
}
groups.push(values.slice(groupStart, index));
}
groups.push(values.slice(index));
return groups;
};
var reconstituteRanges = function(ranges, splits) {
var groups = {}, ctr = 0, diff;
for (var i = 0; i < splits.length; i++) {
diff = splits[i].length
groups["group" + (i + 1)] =
(evens(ranges.slice(ctr, ctr+=(2 * diff))));
}
return groups;
};
return function(ranges, count) {
var values = odds(ranges);
var splits = split(values, count);
return reconstituteRanges(ranges, splits);
}
}());
var ranges = ['a',3,'b',2,'c',1,'d',2,'e',3,'f',3];
console.log(equalSplit(ranges, 3));
//=> {"group1":["a"],"group2":["b","c"],"group3":["d","e","f"]}
You can see it in action on JSFiddle.
This problem is much simpler than an earlier version, although the code is not that much shorter.
But do you really want to let the last group carry all the weight like this? You originally posted wanting them to be closer to equal. In this case, your weighted totals are [3, 3, 8] for a fairly high variance of 16.67, where [['a'],['b','c','d'],['e','f']] would balance better at [3, 5, 6] for a variance of only 4.67. Is this really your requirement, or was this just a way to write simpler code? (Although this code is not too much shorter than my answer to the previous one, it is substantially simpler.)

jquery Generate array with different values for same range

I need to populate three arrays with different values for the same range.
For ex:
Have an array like this
var arr = [1,2,3,4,5,6];
i need this array in format
a[0]=[2,3,4,1,5];
a[1]=[4,3,2,1,5];
a[2]=[2,3,1,5,4];
so three indexes of array show three different array values in order.
I am trying with this below snippets
(function($){
$.fn.shuffle = function() {
return this.each(function(){
var items = $(this).children();
return (items.length)
? $(this).html($.shuffle(items))
: this;
});
}
$.shuffle = function(arr) {
for(
var j, x, i = arr.length; i;
j = parseInt(Math.random() * i),
x = arr[--i], arr[i] = arr[j], arr[j] = x
);
return arr;
}
})(jQuery);
var arr = [1,2,3,4,5,6];
a =[];
b=[];
c=[];
a = $.shuffle(arr);
b = $.shuffle(a);
c = $.shuffle(b);
document.write(a);
document.write(b);
document.write(c);

Categories