I feel like this has a "duh" answer, but
I am using the jQuery Plugin DataTables.net to display a json Google Spreadsheet. You can see it in action here: http://jsfiddle.net/ukoku/jEqu2/2/
I would like to sort the rows by the Location column, which reads in A1, B2 format, like chess. With numbers I know I'd need zero padding, but I have no idea how to add zeros to alphanumeric data, nor do I have any clue how to do it with DataTables instead of regular string.
EDIT: Sorry, I wasn't clear. The place where I thought zeros needed to be added was between the alphabetic character and the number in the Location slot. Currently, Q9 sorts as being after Q14, for example. I need it to sort first by alpha (Ax, Bx), then within that sort as numbers. Normally when I've had 1 show up as higher than 10, it's because I needed to padleft with zeros to get 001 and 010. But I'm not sure how to stick zeros between the numbers for Q009 and Q014, etc., or it that's even the proper solution.
Eventually, the goal is to customize the CSS to display rows with the same location in groups. I honestly have no idea if this is possible either, but since I can't even get the data sorted....
Is this on the right track of what you're after? http://jsfiddle.net/rMUWD/
Here's another way to do it:
var compare = function(a, b) {
return a > b ? 1 : a === b ? 0 : -1;
},
compareAlphanumeric = function (a, b) {
alpha = compare(a.alpha, b.alpha);
numeric = compare(a.numeric, b.numeric);
return (alpha === 1 | (alpha === 0 && numeric === 1)) ? 1 : (alpha === 0 && numeric === 0) ? 0 : -1;
};
jQuery.fn.dataTableExt.oSort['alphaNumeric-asc'] = function(a, b) {
var r = /^([A-Za-z]+)([0-9]+$)/,
a = {
"alpha": a.split(r)[1],
"numeric": parseInt(a.split(r)[2], 10)
},
b = {
"alpha": b.split(r)[1],
"numeric": parseInt(b.split(r)[2], 10)
};
return compareAlphanumeric(a, b);
};
jQuery.fn.dataTableExt.oSort['alphaNumeric-desc'] = function(a, b) {
var r = /^([A-Za-z]+)([0-9]+$)/,
a = {
"alpha": a.split(r)[1],
"numeric": parseInt(a.split(r)[2], 10)
},
b = {
"alpha": b.split(r)[1],
"numeric": parseInt(b.split(r)[2], 10)
};
return compareAlphanumeric(b, a); //reverse a and b for desc
};
Working fiddle here: http://jsfiddle.net/jEqu2/3/
The compare function is your basic comparison function. compareAlphanumeric returns 1, 0, or -1 based on the following truth table:
/*
Alpha Numeric Result
-1 -1 -1
-1 0 -1
-1 1 -1
0 -1 -1
0 0 0
0 1 1
1 -1 1
1 0 1
1 1 1
*/
The bulk of the actual work is done in the oSort functions:
//First declare a RegExp to split the location into an array of [letter, number]
var r = /^([A-Za-z]+)([0-9]+$)/,
//convert the passed "a" parameter to an object containing its letter and number,
//and parse the number portion to an actual number instead of its string representation.
a = {
"alpha": a.split(r)[1],
"numeric": parseInt(a.split(r)[2], 10)
},
//do the same for b
b = {
"alpha": b.split(r)[1],
"numeric": parseInt(b.split(r)[2], 10)
};
//return the alphanumeric comparison
return compareAlphanumeric(a, b);
and in the descending oSort, we only have to switch the order of the parameters passed to compareAlphanumeric.
Related
I need a function that takes a and b both in [0..1] range, and adds a and b and returns the output in [0..1] range, when the sum is above 1 it wraps to zero like mod function.
I tried this but it doesn't work:
function shift(a, b) {
return (a + b) % 1;
}
For example for a = 1 and b = 0, it returns 0 but I want it to return 1.
I think the best you can do is something like:
function normalize(a, b) {
let r = (a + b);
return r === 1 ? 1 : r % 1;
}
This will return 0 when the sum is exactly 0, and 1 when the sum is exactly 1. Other values "wrap" back into the 0 ... 1 range.
I see three conditions here
1) When both of them are 1, the sum will be 2, in which case you have to return 0
2) When the sum is greater than 1, but not 2, in which case subtract 1
3) When the sum is less than 1, return the sum
function f(a,b){
s = (a+b)
if(s == 2)
return s-2
else if (s > 1)
return s-1
else
return s
}
I hope this helps.
So, I've been having trouble trying to prevent toFixed from rounding up numbers, what I want to achieve is that, for a certain number, multiply that number to a specific number and then return the last two digits without rounding up.
I have read the following thread:
javascript - how to prevent toFixed from rounding off decimal numbers.
As a matter of fact, I have tried the solution of Santiago Hernandez.
This is the fiddle: demo
Examples:
6500 * 0.0002 = 1.3
In this case, the result is 1. and does not take the 3 in consideration.
var multiplier = 0.0002;
var num = 500 * multiplier;
var toFixed = function(val, decimals) {
var arr = ("" + val).split(".")
if(arr.length === 1)
return val
var int = arr[0],
dec = arr[1],
max = dec.length - 1
return decimals === 0 ? int :
[int,".",dec.substr(0, decimals > max ? max : decimals)].join("")
}
I imagine is this part:
max = dec.length - 1
What I have tried:
I took out the - 1 and I tried with 10 different types of numbers (987.77, 6600.77, etc) but I wanted to know if there is another type of solution or if at some point the above code will fail for some digits.
An alternative implementation: Add a value, so that math-rounding is changed to rounding-toward-zero:
function toCut ( num, digits )
{
let x = parseFloat("0.5e-"+digits);
return ( num < 0 ? num+x : num-x ).toFixed(digits);
}
That's my toFixed alternative, that don't round numbers, just truncates it or adds zeroes according to given precision. For extra long number it uses JS build-in rounding when precision is to long.
Function works for all problematic number I've found on stack.
function toFixedFixed(value, precision = 0) {
let stringValue = isNaN(+value) ? '0' : String(+value);
if (stringValue.indexOf('e') > -1 || stringValue === 'Infinity' || stringValue === '-Infinity') {
throw new Error('To large number to be processed');
}
let [ beforePoint, afterPoint ] = stringValue.indexOf('.') > -1 ? stringValue.split('.') : [ stringValue, ''];
// Force automatic rounding for some long real numbers that ends with 99X, by converting it to string, cutting off last digit, then adding extra nines and casting it on number again
// e.g. 2.0199999999999996: +('2.019999999999999' + '9999') will give 2.02
if (stringValue.length >= 17 && afterPoint.length > 2 && +afterPoint.substr(afterPoint.length - 3) > 995) {
stringValue = String(+(stringValue.substr(0, afterPoint.length - 1) + '9'.repeat(stringValue.split('.').shift().length + 4)));
[ beforePoint, afterPoint ] = String(stringValue).indexOf('.') > -1 ? stringValue.split('.') : [ stringValue, ''];
}
if (precision === 0) {
return beforePoint;
} else if (afterPoint.length > precision) {
return `${beforePoint}.${afterPoint.substr(0, precision)}`;
} else {
return `${beforePoint}.${afterPoint}${'0'.repeat(precision - afterPoint.length)}`;
}
}
I want to create a javascript function to flip 1's to 0's in a natural number and I'm out of Ideas to achieve this,
Actually, I had a couple of URL's, and I replaced all 0's from a query parameter with 1's and now I no longer know the original parameter value, because there were few 1's in the original parameter value and now both are mixed, so basically I screwed myself,
The only solution for me is to try flipping each 1 to 0 and then 0's to 1's and test each number as the parameter.
This is the parameter value (after replacing 0's with 1's)
11422971
using above input I want to generate numbers as follows and test each of these
11422970
10422971
10422970
01422971
As you can see only 1's and 0's are changing, the change according to binary,
Each position in your string can be one of n characters:
A "0" can be either "0" or "1"
A "1" can be either "0" or "1"
Any other character c can only be c
We can store this in an array of arrays:
"11422971" -> [ ["0", "1"], ["0, "1"], ["4"], ... ]
To transform your string to this format, you can do a split and map:
const chars = "11422971"
.split("")
.map(c => c === "1" || c === "0" ? ["1", "0"] : [ c ]);
Once you got this format, the remaining logic is to create all possible combinations from this array. There are many ways to do so (search for "array combinations" or "permutations"). I've chosen to show a recursive pattern:
const chars = "11422971"
.split("")
.map(c =>
c === "1" || c === "0"
? ["1", "0"]
: [ c ]
);
const perms = ([ xs, ...others ], s = "", ps = []) =>
xs
? ps.concat(...xs.map(x => perms(others, s + x, ps)))
: ps.concat(s);
console.log(perms(chars));
you can do it with a number like a string, and after parse it, something like that
var number= "12551";
number= number.replace("1","0");
The result of number will be "02550"
after that parse number to int
This will generate all permutations.
const generatePermutations = (number) => {
let digits = number.split('');
// find out which digits can be flipped
let digitPositions = digits.reduce((acc, val, i) => {
if (val === '0' || val === '1') acc.push(i);
return acc;
}, []);
// we're going to be taking things in reverse order
digitPositions.reverse();
// how many digits can we flip
let noBits = digitPositions.length;
// number of permutations is 2^noBits i.e. 3 digits means 2^3 = 8 permutations.
let combinations = Math.pow(2, digitPositions.length);
let permutations = [];
// for each permutation
for (var p = 0; p < combinations; p++) {
// take a copy of digits for this permutation
permutations[p] = digits.slice();
// set each of the flippable bits according to the bit positions for this permutation
// i = 3 = 011 in binary
for (var i = 0; i < noBits; i++) {
permutations[p][digitPositions[i]] = '' + ((p >> i) & 1);
}
permutations[p] = permutations[p].join('');
}
return permutations;
};
console.log(generatePermutations('11422970'));
In case your looking for a recursive approach:
function recursive(acc, first, ...rest) {
if(!first) return acc;
if(first == '0' || first == '1') {
var acc0 = acc.map(x => x + '0');
var acc1 = acc.map(x => x + '1');
return recursive([].concat(acc0, acc1), ...rest);
} else {
return recursive(acc.map(x => x + first), ...rest);
}
}
recursive([''], ...'11422971')
// output ["00422970", "10422970", "01422970", "11422970", "00422971", "10422971", "01422971", "11422971"]
This just counts in binary and fills out a template for each value.
function getPossibleValues(str) {
function getResult(n) {
let nIndex = 0;
const strValue = n.toString(2).padStart(nDigits, '0');
return str.replace(rxMatch, () => strValue.charAt(nIndex++));
}
const rxMatch = /[01]/g;
const nDigits = str.length - str.replace(rxMatch, '').length;
const nMax = Math.pow(2, nDigits);
const arrResult = [];
for(let n = 0; n<nMax; n++) {
arrResult.push(getResult(n));
}
return arrResult;
}
console.log(getPossibleValues('11422970'));
Thank you all to respond, you saved my life, btw the approach I used was,
0- convert the number into a string. (so we can perform string operations like split())
1- count the number of 1's in the string (let's say the string is "11422971", so we get three 1's, I used split('1')-1 to count)
2- generate binary of three-digit length,(ie from 000 to 111). three came from step 1.
2- break down the string to single chars, (we'll get
array=['1','1','4','2','2','9','7','1'] )
3- take the first binary number (ie b=0b000)
4- replace first 1 from the character array with the first binary digit of b (ie replace 1 with 0), similarly replace second 1 with the second binary digit of b and so on.
5- we'll get the first combination (ie "00422970")
5- repeat step 3 and 4 for all binary numbers we generated in step 2.
I am doing a php application for a sports event in some cases the minimum value scored is the winner. Like if there is 100mt running event then the winner is the fastest running. Winner has the minimum time taken to complete the race.
But what i am facing that when someone is absent or quit before finish then we are providing score ZERO. In that case when we are going to sort then the First Place will be the ZERO. But that should be at last.
Below is my code in javascript
var sorted = $(".result").sort(function (ib1, ib2) {
return parseFloat($(ib2).val()) - parseFloat($(ib1).val());
});
// Result Names
$('#result_first').val($("#participant"+$(sorted.get(9)).data("section")).val());
$('#result_second').val($("#participant"+$(sorted.get(8)).data("section")).val());
$('#result_third').val($("#participant"+$(sorted.get(7)).data("section")).val());
$('#result_fourth').val($("#participant"+$(sorted.get(6)).data("section")).val());
$('#result_fifth').val($("#participant"+$(sorted.get(5)).data("section")).val());
$('#result_sixth').val($("#participant"+$(sorted.get(4)).data("section")).val());
$('#result_seventh').val($("#participant"+$(sorted.get(3)).data("section")).val());
$('#result_eighth').val($("#participant"+$(sorted.get(2)).data("section")).val());
$('#result_ninth').val($("#participant"+$(sorted.get(1)).data("section")).val());
$('#result_tenth').val($("#participant"+$(sorted.get(0)).data("section")).val());
// Result Numbers
$('#result_first_no').val($(sorted.get(9)).val());
$('#result_second_no').val($(sorted.get(8)).val());
$('#result_third_no').val($(sorted.get(7)).val());
$('#result_fourth_no').val($(sorted.get(6)).val());
$('#result_fifth_no').val($(sorted.get(5)).val());
$('#result_sixth_no').val($(sorted.get(4)).val());
$('#result_seventh_no').val($(sorted.get(3)).val());
$('#result_eighth_no').val($(sorted.get(2)).val());
$('#result_ninth_no').val($(sorted.get(1)).val());
$('#result_tenth_no').val($(sorted.get(0)).val());
Please help me to sort these values and the ZERO values should be last.
The basic idea here is to treat a 0 as Infinity:
var sorted = $(".result").sort(function (ib1, ib2) {
function value(el) {
var x = parseFloat($(el).val());
return x === 0 ? Infinity : x;
}
return value(ib2) - value(ib1);
});
A simple test:
var sorted = [5, 2, 0, 9, 4].sort(function(ib1, ib2) {
function value(el) {
var x = el; // parseFloat($(el).val());
return x === 0 ? Infinity : x;
}
return value(ib2) - value(ib1);
});
console.log(sorted);
$(".result").sort(function (ib1, ib2) {
ib1 = parseFloat($(ib1).val()); ib2 = parseFloat($(ib2).val());
return (ib1 * ib2 === 0) ? ((ib1 === ib2) ? (0) : ((ib1 === 0) ? -1 : 1)) : (ib2 - ib1);
});
If ib1 is 0, then it is "greater" than ib2. Otherwise, if their product is 0 (so ib2 is 0), then ib1 is "smaller" than ib2. If none of them is 0, then your initial logic is applied.
I have this sorting function, but which i use to sort a table, i can sort by dates (which i have removed for simplicity) and strings, but intergers are acting wierd, a common case is that all values could be 0, which will give the array
[0,0,0,0]
this works perfectly in firefox but not in chrome, it changes the order of the rows in my table although they are equal, i have even followed the ECMA standards. Why do chrome change the order anyway? I have also tried using
return (ascending_order ? a - b : b - a)
But with the same result as my more general approach to work with different data types
arr.sort(function(a, b){
var onlydigitsRegex = new RegExp("\d+","g");
if (a.match(onlydigitsRegex) && b.match(onlydigitsRegex)) {
a = parseInt(a);
b = parseInt(b);
} else {
a = a.toLowerCase();
b = b.toLowerCase();
}
return (a === b) ? 0 : (ascending_order ? ((a > b) ? 1 : -1) : ((a < b)? 1 : -1));
});