var a = {28.82:0, 28.91:0, 29.11:0, 30.11:0, 32.22:0, 32.23:0, 32.24:0};
function check(range) // range = 28.90;
if (a[range]){
// do stuff here...
}
In the above scenario as you can notice, the condition will never hold true. I want to write a logic where it takes into account +/- 0.01 of the range to check inside the array.
I had figured driving all array elements through a range check function but that would be too expensive.
Any thoughts?
Let's see if I understand you correctly.
You need to define a tolerance:
var a = [28.82, 28.91, 29.11, 30.11, 32.22, 32.23, 32.24];
function check(range) { // range = 28.90;
for (var i = 0; i < a.length; i++) {
if (Math.abs(a[i] - range) <= 0.01) {
// do stuff here...
}
}
}
a[i] - range will produce the difference between the value and number you're seeking. 0.01 is the set tolarance.
Maybe I'm misunderstanding, but couldn't you do this?
var a = {28.82:"a", 28.91:"b", 29.11:"c", 30.11:"d", 32.22:"e", 32.23:"f", 32.24:"g"};
function check(range){
if (a[range] || a[range+0.01] || a[range-0.01]){
// do stuff here...
}
}
Or is that the approach that you were worried would be too expensive?
Note the logical check if(a[range]) will return false if the value at a[range] equals zero or false. If you want the code to run as long as the property exists, no matter its value, you'll need to modify your condition a bit to account for those edge cases.
Edit: As #SaniHuttunen points out in the comments, you can accomplish this with if(a[range] !== undefined)
function check(range){
function propExists(key){
return a[key] !== undefined;
}
if (propExists(range) || propExists(range+0.01) || propExists(range-0.01){
// do stuff here...
}
}
Would it help to know which two elements it falls between?
var a = [28.82, 28.91, 29.11, 30.11, 32.22, 32.23, 32.24];
function check(arr, range) {
var match = [];
arr.reduce(function(prev, curr){
if ( prev <= range && range <= curr ) { match = [prev, curr]; }
return curr;
})
return match;
}
console.log(check(a, 30.90));
// [30.11, 32.22]
JSFiddle demo.
Related
I want to create a function "palindromes()" which checks whether a value is a palindrome (spelled the same forwards and backwards).
In order to do that, I have created 4 functions, which:
Makes all letters small
Removes all non-letter characters
Reverses the ensuing array, and finally...
Checks whether that array is a palindrome.
See functions bellow:
function makeSmall(input) {
lowerCase = input.toLowerCase();
return lowerCase;
}
function keepOnlyLetters(input) {
var patt1 = /[a-z]/g;
var onlyLetters = input.match(patt1);
return onlyLetters;
}
function reverseArray(array) {
var reversedArray = array.slice().reverse();
return reversedArray;
}
function checkPalindromes(array) {
var reversedArray = array.slice().reverse();
for (let i = 0; i <= array.length; i++) {
if (array[i] != reversedArray[i]) {
return false;
}
}
return true;
}
How do I make sure that the function "palindromes()" takes one value and runs it through all these functions to finally give me an answer (true or false) of whether that value is a palindrome or not?
Best regards,
Beni
There's a point of diminishing returns with functions. When calling the function is just as short as using the body of the function inline, you've probably hit that point. For example, makeSmall(input) is really no improvement to just using input.toLowerCase() inline and will be slower and harder to understand. input.toLowerCase() is already a function; it's just wasted work to wrap it in another function.
Having said that, to answer your question, since all your functions return the value that's input to the next, you can put you functions in an array and call reduce():
function palindromes(input) {
return [makeSmall, keepOnlyLetters, reverseArray, checkPalindromes].reduce((a, c) => c(a), input)
}
So first before trying to do composition at first it sometimes works best to do it sequentially to make sure you understand the problem. As you get better at composition eventually you'll know what tools to use.
function checkPalindrome(string){
return string
.toLowerCase()
.match(/[a-z]/g)
.reverse()
.reduce(function ( acc, letter, index ) {
return acc && string[index] == letter
})
}
checkPalindrome('test') // false
checkPalindrome('tet') // true
Okay good we understand it procedurally and know that there are four steps. We could split those four steps out, however since two steps require previous knowledge of the array state and we don't want to introduce converge or lift just yet we should instead just use a pipe function and combine the steps that require a previous state. The reason for that is eventually functions just lose how much smaller you can make them, and attempting to split those steps up not only hurts readability but maintainability. Those are not good returns on the effort invested to make two functions for that part!
function pipe (...fns){
return fns.reduce( function (f, g){
return function (...args){
return g(
f(...args)
)
}
}
}
All this function does it it pre-loads(composes) a bunch of functions together to make it so that the output of one function applies to the input of the next function in a left to right order(also known as array order).
Now we just need out three functions to pipe:
function bringDown(string){ return string.toLowerCase() } // ussually called toLower, see note
function onlyLetters(string){ return string.match(/[a-z]/g) }
function flipItAndReverseItCompare(arrayLike){ // I like missy elliot... ok?
let original = Array.from(arrayLike)
return original
.slice()
.reverse()
.reduce(function (acc, val, ind){
return acc && val == original[ind]
})
}
Now we can just pipe them
let palindrome = pipe(
bringDown,
onlyLetters,
flipItAndReverseItCompare
)
!palindrome('Missy Elliot') // true... and I never will be
palindrome('Te t') // true
Now you're well on your way to learning about function composition!
You can just string the function calls together like this...
var input = 'Racecar';
if (checkPalindromes(reverseArray(keepOnlyLetters(makeSmall(input))))) {
alert("It's a palindrome");
}
You can just call them in a nested fashion and return the final result in your palindrome function.
Sample Code: (with changes indicated in the comments)
function makeSmall(input) {
// Added var to prevent it from being a global
var lowerCase = input.toLowerCase();
return lowerCase;
}
function keepOnlyLetters(input) {
var patt1 = /[a-z]/g;
var onlyLetters = input.match(patt1);
return onlyLetters;
}
// This function is not really needed and is unused
/*function reverseArray(array) {
var reversedArray = array.slice().reverse();
return reversedArray;
}*/
function checkPalindromes(array) {
var reversedArray = array.slice().reverse();
for (let i = 0; i <= array.length; i++) {
if (array[i] != reversedArray[i]) {
return false;
}
}
return true;
}
// New Palindromes function
function palindromes(input){
return checkPalindromes(keepOnlyLetters(makeSmall(input)));
}
Note:
You don't really need so many functions to do this. I'm putting this here as a strict answer to your exact question. Other answers here show how you can solve this in shorter (and better?) ways
try the following snippet.
function makeSmall(input) {
lowerCase = input.toLowerCase();
return lowerCase;
}
function keepOnlyLetters(input) {
var patt1 = /[a-z]/g;
var onlyLetters = input.match(patt1);
return onlyLetters;
}
function reverseArray(array) {
var reversedArray = array.slice().reverse();
return reversedArray;
}
function checkPalindromes(array) {
var reversedArray = array.slice().reverse();
for (let i = 0; i <= array.length; i++) {
if (array[i] != reversedArray[i]) {
return false;
}
}
return true;
}
var result = checkPalindromes(reverseArray(keepOnlyLetters(makeSmall("Eva, Can I Stab Bats In A Cave"))));
console.log(result);
Notice how functions are called one after the other in one line.
I have an array of characters like this:
['a','b','c','d','f']
['O','Q','R','S']
If we see that, there is one letter is missing from each of the arrays. First one has e missing and the second one has P missing. Care to be taken for the case of the character as well. So, if I have a huge Object which has all the letters in order, and check them for the next ones, and compare?
I am totally confused on what approach to follow! This is what I have got till now:
var chars = ("abcdefghijklmnopqrstuvwxyz"+"abcdefghijklmnopqrstuvwxyz".toUpperCase()).split("");
So this gives me with:
["a","b","c","d","e","f","g","h","i","j","k","l","m",
"n","o","p","q","r","s","t","u","v","w","x","y","z",
"A","B","C","D","E","F","G","H","I","J","K","L","M",
"N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
Which is awesome. Now my question is, how do I like check for the missing character in the range? Some kind of forward lookup?
I tried something like this:
Find the indexOf starting value in the source array.
Compare it with each of them.
If the comparison failed, return the one from the original array?
I think that a much better way is to check for each element in your array if the next element is the next char:
function checkMissingChar(ar) {
for (var i = 1; i < ar.length; i++) {
if (ar[i].charCodeAt(0) == ar[i-1].charCodeAt(0)+1) {
// console.log('all good');
} else {
return String.fromCharCode(ar[i-1].charCodeAt(0)+1);
}
}
return true;
}
var a = ['a','b','c','d','f']
var b = ['O','Q','R','S']
console.log(checkMissingChar(a));
console.log(checkMissingChar(b));
Not that I start to check the array with the second item because I compare it to the item before (the first in the Array).
Forward Look-Ahead or Negative Look-Ahead: Well, my solution would be some kind of that. So, if you see this, what I would do is, I'll keep track of them using the Character's Code using charCodeAt, instead of the array.
function findMissingLetter(array) {
var ords = array.map(function (v) {
return v.charCodeAt(0);
});
var prevOrd = "p";
for (var i = 0; i < ords.length; i++) {
if (prevOrd == "p") {
prevOrd = ords[i];
continue;
}
if (prevOrd + 1 != ords[i]) {
return String.fromCharCode(ords[i] - 1);
}
prevOrd = ords[i];
}
}
console.log(findMissingLetter(['a','b','c','d','f']));
console.log(findMissingLetter(['O','Q','R','S']));
Since I come from a PHP background, I use some PHP related terms like ordinal, etc. In PHP, you can get the charCode using the ord().
As Dekel's answer is better than mine, I'll try to propose somewhat more better answer:
function findMissingLetter (ar) {
for (var i = 1; i < ar.length; i++) {
if (ar[i].charCodeAt(0) != ar[i-1].charCodeAt(0)+1) {
return String.fromCharCode(ar[i-1].charCodeAt(0)+1);
}
}
return true;
}
var a = ['a','b','c','d','f']
var b = ['O','Q','R','S']
console.log(findMissingLetter(a));
console.log(findMissingLetter(b));
Shorter and Sweet.
I have found this library for big integers called jsbn2 by Tom Wu,
and it seemed to work well until I had to use modInverse method.
For some reason it returns undefined no matter what.
The method in the library is:
bnModInverse(m) {
var ac = m.isEven();
if((this.isEven() && ac) || m.signum() == 0) return new BigInteger(0);
var u = m.clone(), v = this.clone();
var a = new BigInteger(1), b = new BigInteger(0), c = new BigInteger(0), d = new BigInteger(1);
while(u.signum() != 0) {
while(u.isEven()) {
u.rShiftTo(1,u);
if(ac) {
if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
a.rShiftTo(1,a);
}
else if(!b.isEven()) b.subTo(m,b);
b.rShiftTo(1,b);
}
while(v.isEven()) {
v.rShiftTo(1,v);
if(ac) {
if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
c.rShiftTo(1,c);
}
else if(!d.isEven()) d.subTo(m,d);
d.rShiftTo(1,d);
}
if(u.compareTo(v) >= 0) {
u.subTo(v,u);
if(ac) a.subTo(c,a);
b.subTo(d,b);
}
else {
v.subTo(u,v);
if(ac) c.subTo(a,c);
d.subTo(b,d);
}
}
if(v.compareTo( BigInteger.ONE ) != 0) return new BigInteger(0);
if(d.compareTo(m) >= 0) return d.subtract(m);
if(d.signum() < 0) d.addTo(m,d); else return d;
// MODIFIED BY ATS 2008/11/22 FOR COMPATIBILITY TO Flash ActionScript
// if(d.signum() < 0) return d.add(m); else return d;
if(d.signum() < 0) return d.ope_add(m); else return d;
};
I used it with very long numbers, for ex.
var a = new BigInteger("26243431849380303664210129223718904471391758038739441955848319764858899645035");
var b = new BigInteger("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", 16);
(fixed b value, ty Rudy Velthuis)
But the a.modInverse(b) returns undefined.
Is there something wrong with the method, that needs to be fixes?
How can I make it work?
OK.. after like hundreds of logs and stuff I finally found what is the problem in my case.
While the example value that I gave in question itself seems to actually work, there is a different problem with the method modInverse (again.. sorry if that mislead someone).
The problem with it (the modInverse method in jsbn2) is that it doesn't know what to do with negative numbers (while the Java modInverse knows).
My solution to this was to check if the value that I will give it is positive and if not, I prepared it (thanks to this topic for explaining how):
if(a.compareTo(ZERO)<0)
{
a = a.negate(); //make it positive
a = a.mod(b); //get modulo
a = b.subtract(a); //get remainder of modulo
}
I don't know if this is the best solution to it (surely not) but it seems to work.
The result values that I tested are now equal to those of Java's modInverse.
Hope this helps anyone who get lost just like me here :3
Below is just a section of my code but I know it's problematic because I can't get it to return any value except 'undefined'. I have been over this for hours and cannot figure it out.
I want to be able to input a number and have its factors pushed to an array. I have tested it by alerting the first item in the array and I get nothing. I'm sure this is a pretty easy but I just can't figure it out. Here is the code:
var numberInQuestion = prompt("Of what number are you wanting to find the largest prime factor?");
//determine factors and push to array for later use
var factorsArray = [];
function factors(numberInQuestion){
for(var i = 2; i < numberInQuestion-1; i++){
if(numberInQuestion % i === 0){
return factorsArray.push[i];
} else {
continue;
}
}
};
factors(numberInQuestion);
alert(factorsArray[0]);
Thanks for any help!
you can only return one value
you must use (), not [] for calling push
factorsArray should be local to factors (put the definition inside the function)
the else { continue; } is useless
Here is the fully corrected code:
var numberInQuestion = prompt("Of what number are you wanting to find the factors of?");
//determine factors
function factors(numberInQuestion){
var factorsArray = []; // make it local
for (var i = 2; i < numberInQuestion-1; i++){
if(numberInQuestion % i === 0){
factorsArray.push(i); // use (), and don't return here
} // no need for else { continue; } because it's a loop anyway
}
return factorsArray; // return at the end
};
var result = factors(numberInQuestion); // assign the result to a variable
alert(result);
Here's a JSFiddle.
You have an error in your pushing syntax. Correct syntax for pushing is -
factorsArray.push(i);
Also returning immediately from the function after finding the first divisor will not give you the full list. You probably want to return after you've found out all the divisors.
Taking all of the above into consideration, you should rewrite your function as follow -
function factors(numberInQuestion){
for(var i = 2; i < numberInQuestion - 1; i++){
if(numberInQuestion % i === 0) {
factorsArray.push(i);
}
}
}
and you will be OK.
You've coded this so that when you find the first factor your function returns immediately. Just get rid of the return keyword in that statement. (What "return" means in JavaScript and other similar languages is to immediately exit the function and resume from where the function was called.)
Oh, also, you call functions (like .push()) with parentheses, not square brackets.
The function should not return when pushing to the array. Return the array after executing the loop. The else clause is also unnecessary.
var numberInQuestion = prompt("Of what number are you wanting to find the largest prime factor?");
function factors(numberInQuestion){
var factorsArray = [];
for(var i = 2; i < numberInQuestion-1; i++){
if(numberInQuestion % i === 0 && isPrime(i)){
factorsArray.push(i);
}
}
return factorsArray;
};
var factors = factors(numberInQuestion);
alert(factors[factors.length-1]);
//From: http://stackoverflow.com/questions/11966520/how-to-find-prime-numbers
function isPrime (n)
{
if (n < 2) return false;
var q = Math.sqrt (n);
for (var i = 2; i <= q; i++)
{
if (n % i == 0)
{
return false;
}
}
return true;
}
Given the purpose of the example two items must be considered
The code does not determine if the number is actually prime. The code will return the smallest factor possible since the loop starts at two and increments, then returns the first element in the array. The largest factor would actually be the last element in the array. I have corrected the example to find the greatest prime factor. You can test it via this fiddle: http://jsfiddle.net/whKGB/1/
I've got an in page text search using JS, which is here:
$.fn.eoTextSearch = function(pat) {
var out = []
var textNodes = function(n) {
if (!window['Node']) {
window.Node = new Object();
Node.ELEMENT_NODE = 1;
Node.ATTRIBUTE_NODE = 2;
Node.TEXT_NODE = 3;
Node.CDATA_SECTION_NODE = 4;
Node.ENTITY_REFERENCE_NODE = 5;
Node.ENTITY_NODE = 6;
Node.PROCESSING_INSTRUCTION_NODE = 7;
Node.COMMENT_NODE = 8;
Node.DOCUMENT_NODE = 9;
Node.DOCUMENT_TYPE_NODE = 10;
Node.DOCUMENT_FRAGMENT_NODE = 11;
Node.NOTATION_NODE = 12;
}
if (n.nodeType == Node.TEXT_NODE) {
var t = typeof pat == 'string' ?
n.nodeValue.indexOf(pat) != -1 :
pat.test(n.nodeValue);
if (t) {
out.push(n.parentNode)
}
}
else {
$.each(n.childNodes, function(a, b) {
textNodes(b)
})
}
}
this.each(function() {
textNodes(this)
})
return out
};
And I've got the ability to hide columns and rows in a table. When I submit a search and get the highlighted results, there would be in this case, the array length of the text nodes found would be 6, but there would only be 3 highlighted on the page. When you output the array to the console you get this:
So you get the 3 tags which I was expecting, but you see that the array is actually consisting of a [span,undefined,span,undefined,undefined,span]. Thus giving me the length of 6.
<span>
<span>
<span>
[span, undefined, span, undefined, undefined, span]
I don't know why it's not stripping out all of the undefined text nodes when I do the check for them. Here's what I've got for the function.
performTextSearch = function(currentObj){
if($.trim(currentObj.val()).length > 0){
var n = $("body").eoTextSearch($.trim(currentObj.val())),
recordTitle = "matches",
arrayRecheck = new Array(),
genericElemArray = new Array()
if(n.length == 1){
recordTitle = "match"
}
//check to see if we need to do a recount on the array length.
//if it's more than 0, then they're doing a compare and we need to strip out all of the text nodes that don't have a visible parent.
if($(".rows:checked").length > 0){
$.each(n,function(i,currElem){
if($(currElem).length != 0 && typeof currElem != 'undefined'){
if($(currElem).closest("tr").is(":visible") || $(currElem).is(":visible")){
//remove the element from the array
console.log(currElem)
arrayRecheck[i] = currElem
}
}
})
}
if(arrayRecheck.length > 0){
genericElemArray.push(arrayRecheck)
console.log(arrayRecheck)
}
else{
genericElemArray.push(n)
}
genericElemArray = genericElemArray[0]
$("#recordCount").text(genericElemArray.length + " " +recordTitle)
$(".searchResults").show()
for(var i = 0; i < genericElemArray.length; ++i){
void($(genericElemArray[i]).addClass("yellowBkgd").addClass("highLighted"))
}
}
else{
$(".highLighted").css("background","none")
}
}
If you look at the code below "//check to see if we need to do a recount on the array length. ", you'll see where I'm stripping out the text nodes based off of the display and whether or not the object is defined. I'm checking the length instead of undefined because the typeof == undefined wasn't working at all for some reason. Apparently, things are still slipping by though.
Any idea why I'm still getting undefined objects in the array?
My apologies for such a big post!
Thanks in advance
I've modified your eoTextSearch() function to remove dependencies on global variables in exchange for closures:
$.fn.extend({
// helper function
// recurses into a DOM object and calls a custom function for every descendant
eachDescendant: function (callback) {
for (var i=0, j=this.length; i<j; i++) {
callback.call(this[i]);
$.fn.eachDescendant.call(this[i].childNodes, callback);
}
return this;
},
// your text search function, revised
eoTextSearch: function () {
var text = document.createTextNode("test").textContent
? "textContent" : "innerText";
// the "matches" function uses an out param instead of a return value
var matches = function (pat, outArray) {
var isRe = typeof pat.test == "function";
return function() {
if (this.nodeType != 3) return; // ...text nodes only
if (isRe && pat.test(this[text]) || this[text].indexOf(pat) > -1) {
outArray.push(this.parentNode);
}
}
};
// this is the function that will *actually* become eoTextSearch()
return function (stringOrPattern) {
var result = $(); // start with an empty jQuery object
this.eachDescendant( matches(stringOrPattern, result) );
return result;
}
}() // <- instant calling is important here
});
And then you can do something like this:
$("body").eoTextSearch("foo").filter(function () {
return $(this).closest("tr").is(":visible");
});
To remove unwanted elements from the search result. No "recounting the array length" necessary. Or you use each() directly and decide within what to do.
I cannot entirely get my head around your code, but the most likely issue is that you are removing items from the array, but not shrinking the array afterwards. Simply removing items will return you "undefined", and will not collapse the array.
I would suggest that you do one of the following:
Copy the array to a new array, but only copying those items that are not undefined
Only use those array items that are not undefined.
I hope this is something of a help.
Found the answer in another post.
Remove empty elements from an array in Javascript
Ended up using the answer's second option and it worked alright.