I am really struggling with this, so maybe some of you have some beautiful hints?
What I want to do
I want to create a table with two columns ("name" and "rating"). I've got 5 rows.
2 of these rows should have a random "rating" between 6-10
2 other rows should have a random "rating" between 1-5
1 row (the last one) should have a random rating between 7-10.
Until this point there is no problem: This is my jsFiddle so far: http://jsfiddle.net/HT89v/2/
BUT:
I want to shuffle the "ratings" of the first 4 rows, so that the first two rows don't always have a very high "rating" and the 3rd and 4th row don't always have a very low "rating". I want to randomly shuffle them.
The 5th row should not be affected. .
I tried to implement the .shuffle plugin in the jsfiddle but I have no idea what I am doing wrong.
function noNorm(){
document.getElementById("rating4").innerHTML = [Math.floor(Math.random()*5) + 6];
for (var i = 0; i <= 1; i++){
document.getElementById("rating"+i).innerHTML = [Math.floor(Math.random()*5) + 6];
};
for (var i = 2; i <= 3; i++){
document.getElementById("rating"+i).innerHTML = [Math.floor(Math.random()*5) + 1];
};
};
noNorm();
jQuery(function($){
$('#rating0', '#rating1', '#rating2', '#rating3').shuffle();
});
(function($){
$.fn.shuffle = function() {
return this.each(function(){
var items = $(this).children().clone(true);
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);
Thank you very very much!
There are many solutions to shuffle arrays with javascript.
If I understand your problem correcty, this should do the trick: http://jsfiddle.net/HT89v/6/
I shuffle the whole ratings[] array before giving a value to ratings[4] so that the 5th row is not affected.
Related
I am attempting to write a page which has a table where the user can input a number in each cell, it would then display a total of that row with the lowest two values of that row subtracted. The code creates the array, finds the total of the array and the lowest 2 values (low and low2 in the code below). However when I try to take the two lowest values from the total, i get an error. I think i have found the error as testing the values using isNaN i find that the sum of the array is not a number, which doesn't seem to make sense to me. Here is where I got up to with the code:
table = document.getElementsByTagName("tbody")[0];
allrows = table.getElementsByTagName("tr");
for (i=0; i < allrows.length; i++) {
rowTotal = 0;
rowArray =[];
for (ii=0; ii < allrows[i].getElementsByTagName("input").length; ii++) {
rowTotal = rowTotal + Number(allrows[i].getElementsByTagName("input")[ii].value);
rowArray.push(Number(allrows[i].getElementsByTagName("input")[ii].value));
var tots=rowTotal;
}
rowArray.sort(function(a, b){return b-a});
var low = $(rowArray[rowArray.length-2]);
var low2 = $(rowArray[rowArray.length-1]);
rowTotaladj = rowTotal- low - low2;
$(".row-total:eq("+(i-1)+")").html(rowTotaladj);
}
Here is a link to a previous version of the page which correctly displays the total (rowTotal) but does not have the total minus the lowest two values in:
Any explaination as to why the sum is not a number and help with the code would be much appreciated.
Since you're already using jQuery, you can use the following code to achieve what you want:
// When an <input> is changed:
$('table input').on('change', function() {
var sum = 0,
vals = [ ];
$(this).parents('table').find('input').each(function() {
var val = parseInt( $(this).val() ) || 0;
vals.push( val );
sum+= val;
});
// Now sort the array:
vals.sort();
total = sum - vals[0] - vals[1];
$('tfoot td').html( total );
});
jsFiddle Demo
I'm trying to get a function to loop through data in two tables and put them into an object. The first for-loop that goes through the first table does this fine, but the second for-loop that goes through the second table spits out an empty object when there's only 1 row to go through.
However, when there is more than 1 row, then all of the objects have the values as the second row.
I really don't understand what I'm doing wrong here:
function foo(){
var rows = $('#table1').find('tr');
var array1 = [];
for(var i = 1; i < rows.length-1; i++){
var row = $(rows[i]).find('input');
var o = {
name : $(row[0]).val(),
bday : $(row[1]).val(),
parent : $(row[2]).val(),
parentBDay : $(row[3]).val(),
parentNumber : $(row[4]).val()
};
array1.push(o);
}
var array2 = [];
rows = $('#table2').find('tr');
for(var j = 1; j < rows.length-1; j++){
var row = $(rows[i]).find('input');
var o = {
name : $(row[0]).val(),
bday : $(row[1]).val(),
phoneNumber : $(row[2]).val()
};
console.log('wtf: ' + JSON.stringify(o));
array2.push(o);
}
}
Your problem is that your indexes in the for cycle are not looping well. You start the for cycle from 1, which, in case you want to use the very first element, then it is wrong. Note, that indexing begins from 0. If you miss the very first element on purpose, because it is a header row or something, then this is not a problem. However, the end sign, like
< rows.length - 1
is clearly wrong. Let's suppose, the number of rows is 50. Then its last index is 50 - 1 = 49. If you loop from one until you reach the number below 50 - 1, then your last index will be 48 and you will miss the very last element. Your condition should be either < rows.length or <= rows.length - 1.
My title might be terrible, but I can explain exactly what I want here. First of all, I am challenging myself to something very specific. Even if you guess what I'm trying to accomplish, please keep your answers on topic to what I am asking here, and not the overall problem I am solving.
I have a string of 25 generated letters.
I get an index of a letter via str.indexOf(c) and let's say that index is 16.
Visualize that str is a linear representation of a 5x5 table, thus an index of 16 would be the 4th row, 2nd column of that table.
I'm trying to find a way to find the row and column using javascript without looping through like this:
var row = 1;
var index = str.indexOf(c) + 1;
while(index > 5) {
index = index - 5;
row++;
}
With the above code, if index starts as 16, my end result will be row 4, index 2 - which is what I want. It just feels like there should be a way to do this with an algorithm instead of a loop.
Any thoughts?
You are replicating division and modulus in this code sample, you can achieve the same thing by doing row = Math.floor(index / 5) and col = index % 5.
var index = parseInt(prompt('Numeric Index'));
var row = Math.floor(index / 5) + 1;
var col = index % 5;
alert('[ ' + col + ', ' + row + ' ]');
Why not just use maths?
var index = 16;
var columnsPerRow = 5;
row = parseInt(index / columnsPerRow) + 1;
column = index % columnsPerRow + 1;
Instead of using a loop, you can just create a function
function findPosition(index, cols) {
var rowIndex = parseInt(index/cols) + 1;
var colIndex = index % cols;
return {rowIndex: rowIndex, colIndex: colIndex}
}
So in your case string index is 17, and your matrix col is 5
you will be calling findPosition(17, 5) and it will return {rowIndex: 4, colIndex: 2}
try this, you can just use the remainder (or modulus) to find the column and the whole number to find the row.
function getPosition(str, character, gridWidth) {
var index = str.indexOf(character);
var row = Math.floor(index/gridWidth);
var col = index%gridWidth;
return {row:row, col:col};
}
Then use it like this
var str = "hello sir";
console.log(getPosition(str, "i", 3));
You can caluclate the position, this solution depend on Matrix start at 0, 0 not 1, 1 add 1 to row and column if you want to start from index 1:
array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
number = 16
per_row = 5
index = array.indexOf(number)
row = Math.floor(index/ per_row )
column = index % per_row
I'm working on adding better visualization to data tables that I have so that the highest numbers in that column will have a green CSS background, and the lowest values in that column will have a red CSS background.
I've come pretty far, I am basically down to the last bit. I'm a native PHP dev, so I may be messing up the integer comparison as well as not doing the final jQuery selector correctly. The code selects all the elements in the same column, finds the min and max, calculates the step value, and calculates how many steps above the minimum the current element is. All I need to do now is apply a css class based on the steps. It will be something like values in the 0-5% range will have css group 0, 5-10 will have css group 1, 10-15 group 2, 95-100 group 20. All that css is on the fiddle. I am successfully applying a CSS class, but not to a single cell, it does it for the whole column
$(document).on('click', '#dvData td.color', function() {
var ndx = $(this).index() + 1;
//alert('Val of ndx: ' + ndx);
var thisCol = $('#dvData td:nth-child(' +ndx+ ')');
var arr = thisCol.slice(1, thisCol.length);
var columnDataArr = new Array();
alert("Number of rows: " + arr.length);
//alert("First Row: " + arr[0].innerHTML);
for(var i = 0, x = arr.length; i < x; i++){
columnDataArr[i] = arr[i].innerHTML;
}
var colorsArray = ["63BE7B","72C27B","82C77C","91CB7D","A1D07E","B1D47F","C0D980","D0DD81","DFE282","EFE683","FFEB84","FFDE82","FED280","FDC47D","FDB87B","FCAA78","FB9D75","FB9073","FA8370","F9776E","F8696B"];
var max = Math.max.apply(Math, columnDataArr),
min = Math.min.apply(Math, columnDataArr),
range = max - min,
step_val = range/100;
alert("Step Value:" + step_val);
for(var i = 0, x = arr.length; i < x; i++){
var thisPercentile = parseInt((columnDataArr[i] - min) / step_val);
alert("Percentile:" + thisPercentile);
switch ( thisPercentile ) {
// yes this looks terrible, but i can't seem to get the case to work
// with: case(thisPercentile) <= 5:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
alert("Below 10th Percentile");
break;
case parseInt(90):
alert("90th Percentile");
//arr[2].addClass('group10') // doesn't work
break;
}
}
arr.addClass('group20');
});
So the two issues are how to deal with passing a Range to a switch statement (or giving up and using ifs and else ifs), and what the correct selector is to target the current table cell. I have my code on jsfiddle.
Since your value range goes from 0-100 and your group names go from group0-group20, you can do a bit of math and forego the switch/if statement entirely.
If you get the floor of ( value / 5 ), you will end up with 0 for 0-4, 1 for 5-9, ... 19 for 95-99, 20 for 100.
After getting the floor value, you can concatenate the result with the group name and add the result clsas like below:
Note: You created a vanilla JS array with splice, so you'll need to wrap arr[i] with $( ) to turn it into a jQuery object.
jsfiddle: http://jsfiddle.net/7Luwyyxr/2/
for(var i = 0, x = arr.length; i < x; i++){
var thisPercentile = parseInt((columnDataArr[i] - min) / step_val);
alert("Percentile:" + thisPercentile);
// added this stuff
var gnum = Math.floor( thisPercentile/5 ); // returns 0 for 0-4, 1 for 5-9, ...
//alert("Group Num: " + gnum);
$(arr[i]).addClass('group'+gnum); // appends class to array index
}
This solution will distinguish between 20 different numbers before assigning 2 numbers the same colors. It works with percentile (e.g. the percent of items it is greater than or equal to) to assign a color. The top value would always get the same class, and the lowest would always get the same class. The numbers in between would depend on each other to get a class assigned.
for(var i = 0, x = columnDataArr.length; i < x; i++){
var greaterThan = 0;
var curNum = columnDataArr[i];
for(var j = 0, x = columnDataArr.length; j < x; j++){
if(curNum <= columnDataArr[j]){
greaterThan += 1;
}
}
var percentile = Math.round((greaterThan*100)/columnDataArr.length);
var group = Math.round(percentile/5);
$(arr[i]).addClass('group'+group);
}
And heres a fiddle : http://jsfiddle.net/7Luwyyxr/4/
I want to try and sum up distinct value from a list.. currently i am able to do so if theres only 2 similar record. If theres more than 2 i am not able to do the checking. Following is the javascript code:
function validateData(){
var total = document.frm.size.value;
var msg="";
var tbxA;
var tbxB;
var tbxA2;
var tbxB2;
var tbxC;
var totalValue =0;
var repeatedValue= 0;
var row = 0;
var row2 = 0;
for(var i=0; i<parseInt(total); i++){
tbxA = document.getElementById('tbx_A'+i).value;
tbxB = document.getElementById('tbx_B'+i).value-0;
tbxC = document.getElementById('tbx_C'+i).value;
for(var j=i+1; j<parseInt(total); j++){
tbxA2 = document.getElementById('tbx_A'+j).value;
tbxB2 = document.getElementById('tbx_B'+j).value-0;
if (tbxA==tbxA2) {
totalValue = tbxB + tbxB2;
}
if (totalValue != tbxC) {
repeatedValue= 1;
row = i;
row2 = j;
msg+="*total value does not add up at row " +(row2+1);
break;
}
}
if(repeatedValue== 1){
break;
}
}
return msg;
}
For example A:type of fruit, B: total of each fruit, C: how many bought at a time
total of C should be equal to B. i.e Apple: 3+3+4 = 10. So if the total is not equals to 10 it should prompt me an error.
A B C
Apple 10 3
Orange 10 10
Apple - 3
Apple - 4
My code above will prompt error bt it doesnt go beyond 2nd occurence of Apple.
So yes, how should i go about to ensure it loop through the whole list to sum up all similar values?
Thanks in advance for any possible help!
Try this:
var total = +document.frm.size.value,
data = {};
for(var i=0; i<total; ++i) {
var key = document.getElementById('tbx_A'+i).value;
data[key] = data[key] || {B:0, C:0};
data[key].B += +document.getElementById('tbx_B'+i).value || 0;
data[key].C += +document.getElementById('tbx_C'+i).value || 0;
}
for(var i in data) {
if(data.hasOwnProperty(i) && data[i].B != data[i].C) {
return "total value does not add up";
}
}
return "";
Some comments:
parseInt (and parseFloat) is very slow. + operator before string converts it to a number much faster. But if you really want to make sure the numbers are integers, use Math.floor(), Math.round(), Math.ceil() or the faster but illegible |0.
In case you really want parseInt (e.g. you want to convert '123foobar' into 123), always use a radix. For example: parseInt('123', 10)
Avoid doing calculations at the condition of a loop, because they run at each iteration. Just do the calculation once before the loop and save the result in a variable.