So, for my own knowledge, and because I love looking at things from a different perspective...
I have the following bite of Javascript code, which for this problem's intents and purposes will only ever receive strings formatted like this: "wordone wordtwo":
function inName(inputName) {
return inputName.split(" ")[1].toUpperCase();
}
However, this only returns half of what I want ("WORDTWO"). I desire to return the original string with a single change: the space-separated second word returned through the toUpperCase(); and then re-concatenated to the untouched first word.
I also want to unnecessarily run all of the operations on the return line. My brain says this is possible, given how as the compiler reads the line from left to right and makes adjustments to the available member functions based on what has resolved. Also everything in Javascript is an object, correct?
Help me out for my own curiosity's sake, or bash me over the head with my own misconceptions.
Here is a solved version of the above question using 'normal' statements:
function inName(inputName) {
var nameArray=inputName.split(" ");
nameArray[1]=nameArray[1].toUpperCase();
return nameArray.join(" ");
}
One line with substr, indexOf and a variable on the fly ;-)
function inName(inputName) {
return inputName.substr(0, (index = inputName.indexOf(' '))) + inputName.substr(index).toUpperCase();
}
Here's another option which avoids the regular expression:
function inName(inputName) {
return inputName.split(' ').map(function(v,i){return i?v.toUpperCase():v;}).join(' ');
}
This does the same split as the original code, then maps the parts to a function which returns the value at index 0 unchanged but the value at index 1 in upper case. Then the two results are joined back together with a space.
As others have said, a longer, clearer version is better in practice than trying to come up with a clever one-liner. Defining a function inside the return statement feels like cheating anyway ;-)
Something like this almost seems like it belongs on Code Golf, but here's my take:
function inName(inputName) {
return inputName.replace(/ .*/,function(m) {return m.toUpperCase();});
}
Interesting. Here is my take on the problem
function justDoIt(str){
return [str = str.split(" ") , str.pop().toUpperCase()].join(" ");
}
Creates a new array, str is split and reassigned as an array, and the first item of the new array, then the second new array item pops the last word, makes it uppercase, puts it into the new array. Then joins the array [["wordOne"],"WORDTWO"].join(" ")
Related
I've been asked to optimize the speed of my query. I currently have this regex in my query, which is checking for a pattern and returning substring within that pattern. To clarify I have a table with multiple columns that I have to look through to check for this value: [v= and return the numbers within that list.
This is looking through several 'name..' columns that look something like this: xyzzy [v=123] but I only want to return 123, the below works:
COALESCE(REGEXP_SUBSTR(NAME, '[[]v=([0-9]+)', 1, 1, 'ie'),
REGEXP_SUBSTR(NAME_5, '[[]v=([0-9]+)', 1, 1, 'ie'),
REGEXP_SUBSTR(NAME_4, '[[]v=([0-9]+)', 1, 1, 'ie')) as display_vertical_code
but to optimize this, I thought of maybe creating a function unfortunately I don't know javascript :/ and I don't know if the formatting is correct I'm having some difficulties creating it, this is what I've tried, can someone tell me if I'm missing something?
CREATE OR REPLACE FUNCTION dfp.regex(NAME VARCHAR)
RETURNS OBJECT
LANGUAGE javascript
STRICT AS '
return new RegExp(NAME,"[[]v=([0-9]+)",1 ,1,"ie")
';
When I try to use the above function in my below query:
COALESCE(
GET(DFP.REGEX(NAME)),
GET(DFP.REGEX(NAME_5)),
GET(DFP.REGEX(NAME_4)),
GET(DFP.REGEX(NAME_3)),
GET(DFP.REGEX(NAME_2)),
GET(DFP.REGEX(NAME_1)),
GET(DFP.REGEX(NAME_0))
) as display_vertical_code
I see this error:
error line 3 at position 8 not enough arguments for function
[GET(REGEX(Tablename.NAME))], expected 2, got 1
This should do it.
CREATE OR REPLACE FUNCTION regex(NAME VARCHAR)
RETURNS string
LANGUAGE javascript
STRICT IMMUTABLE AS
$$
const regex = /[[]\s{0,5}v\s{0,5}=\s{0,5}([0-9]+)/i;
let s = NAME.match(regex);
if (s != null) {
return s[0].split('=')[1].trim();
} else {
return null;
}
$$;
select regex('xyzzy [v=123]');
-- Alternate permutation
select regex('xyzzy [ v = 123]');
You want to return a string, not an object. Adding the IMMUTABLE option tells Snowflake that the same input results in the same output every time. It can sometimes help with performance.
Edit... This one's a bit more fault tolerant and allows whitespace (if that could be a problem). If you want to get rid of allowing whitespace, delete the \s{0,5} expressions.
I am making a trivia system, and the variable triviaA is changed to the updated Answer every time there is a new question. I was wondering how I could use Regex to make it so that if triviaA = 'eagle' then if someone submitted the answer as eagle but with a small spelling mistake, the if statement would still return both the triviaA answer and the players answer return true.
I'm new to Regex, please excuse my mistakes.
You can dynamically build a regular expression that matches all possible "errors" (wrong/missing/extra letter) and apply it to the source:
function fuzzyContains(word, str) {
let r = [];
for (let i = 0; i < word.length; i++) {
// wrong letter
r.push(word.slice(0, i) + '[a-z]' + word.slice(i + 1));
// missing letter
r.push(word.slice(0, i) + '' + word.slice(i + 1));
// extra letter
r.push(word.slice(0, i) + '[a-z]' + word.slice(i));
}
return new RegExp(r.join('|')).test(str)
}
console.log(fuzzyContains('eagle', 'fly, ewgle, fly'))
console.log(fuzzyContains('eagle', 'fly, eagl, fly'))
console.log(fuzzyContains('eagle', 'fly, eaggle, fly'))
console.log(fuzzyContains('eagle', 'fly, eagly, fly'))
See https://norvig.com/spell-correct.html for other interesting ideas.
This would actually be quite difficult to do with RegEx. However, there's a concept in computing called "edit distance", which is a measure of how "similar" two strings are, and there are known algorithms to calculate that. Which means there are Node packages to calculate it :)
For instance, there's the aptly named Node package edit-distance: https://www.npmjs.com/package/edit-distance (Note: edit distance is sometimes called Levenshtein edit distance, named after the man who first studied it.)
I'll give you an example using that package; other packages may work somewhat differently to calculate the same thing.
There are three types of changes between two strings: an insertion, where a character is added in one that's not in the other; a deletion, where a character is removed in one that's there in the other; and an update/substitution, where a letter is changed between the strings. Using the edit-distance package, you define a function that assigns a cost to each of these types of changes. Then you call the package's levenshtein method, passing it the two strings and the three functions, and it returns an object with a distance property that is the sum score.
Assuming your cost functions return non-negative values, a score of 0 means the two strings are identical, and higher numbers mean they're more different. So you can use this to compare the entered value with the correct string and, if the result is lower than a certain threshold, accept it as "correct excluding typos".
I'm creating a few specific functions for a compiler I'm working on, But certain restrictions within the compiler's nature will prevent me from using native JavaScript methods like Array.prototype.pop() to perform array pops...
So I decided to try and write some rudimentary pseudo-code to try and mimic the process, and then base my final function off the pseudo-code... But my tests seem to fail... based on the compiler's current behavior, it will only allow me to use array.length, array element assignments and that's about it... My code is below...
pop2 = function(arr) {
if(arr.length>0){
for(var w=undefined,x=[],y=0,z=arr.length;y<=z;y++){
y+1<z?(x[y]=arr[y]):(w=arr[y],arr=x);
}
}
return w;
}
Arr = [-1,0,1,2];
// Testing...
console.log(pop2(Arr)); // undefined... should be 2
console.log(Arr); // [-1,0,1,2]... should be [-1,0,1]
I'm trying to mimic the nature of the pop function but can't seem to put my finger on what's causing the function to still provide undefined and the original array... undefined should only return if an initial empty array is sent, just like you would expect with a [].pop() call...
Anyone have any clues as to how I can tailor this code to mimic the pop correctly?
And while I have heard that arr.splice(array.length-1,1)[0]; may work... the compiler is currently not capable of determining splice or similar methods... Is it possible to do it using a variation of my code?
Thanks in advance...
You're really over-thinking [].pop(). As defined in the specs, the process for [].pop() is:
Get the length of the array
If the length is 0
return undefined
If length is more than 0
Get the item at length - 1
Reduce array.length by 1
Return item.
(... plus a few things that the JavaScript engine needs to do behind the scenes like call ToObject on the array or ensure the length is an unsigned 32-bit integer.)
This can be done with a function as simple as the one below, there's not even a need for a loop.
function pop(array) {
var length = array.length,
item;
if (length > 0) {
item = array[length - 1];
array.length -= 1;
}
return item;
}
Edit
I'm assuming that the issue with the compiler is that Array.prototype.pop isn't understood at all. Re-reading your post, it looks like arrays have a pop method, but the compiler can't work out whether the variable is an array or not. In that case, an even simpler version of this function would be this:
function pop(array) {
return Array.prototype.pop.call(array);
}
Try that first as it'll be slightly faster and more robust, if it works. It's also the pattern for any other array method that you may need to use.
With this modification, it works:
http://jsfiddle.net/vxxfxvpL/1/
pop2 = function(arr) {
if(arr.length>0){
for(var w=undefined,x=[],y=0,z=arr.length;y<=z;y++){
if(y+1<z) {
(x[y]=arr[y]);
} else {
(w=arr[y],arr=x);
break;
}
}
}
return w;
}
Arr = [-1,0,1,2];
// Testing...
console.log(pop2(Arr)); // 2
The problem now is to remove the last element. You should construct the original array again without last element. You will have problems with this because you can't modify the original array. That's why this tasks are maded with prototype (Array.prototype.pop2 maybe can help you)
Kind of an odd request, I know. But I've been looking for a solution to this for quite a while now. This is the effect I'm looking for:
var myString = "Hello I am randomly capitalized"
Desired function result:
hElLO i aM rAnDOmlY caPiTAlizED
I imagine this is best done with javascript arrays in one way or another. Just looking for some creative ideas. Thank you!
Here's one way
myString.split('').map(function(c){
return c[Math.round(Math.random())?'toUpperCase':'toLowerCase']();
}).join('');
You could add this as a prototype method on the string object for easy access if desired:
String.prototype.toRandomCase = function() {
return this.split('').map(function(c){
return c[Math.round(Math.random())?'toUpperCase':'toLowerCase']();
}).join('');
}
Then access by
console.log(myString.toRandomCase());
A bit of an explanation of how this works:
String.split method is used to split the string into an array of individual characters.
Array.map function is used. This takes a callback function that is applied to each item in an array, and returns a new resulting array with each value returned by the map function.
Inside the map function
Math.round(Math.random()) is used for randomness
The result of that is used with a ternary operator to get toLowerCase or toUpperCase
Math.Round(Math.random())?'toLowerCase':'toUpperCase'
The result of the ternary operator is used to access the relevant function property by array deferencing of the character, then called. c[<ternary here>]()
Finally it uses Array.join method on the result of the map function call to join the resulting array back into a string.
Code golf (efficiency)
RobG's answer has a more efficient approach than mine (please upvote his answer)
String.prototype.toRandomCase = function() {
return this.toLowerCase().split('').map(function(c){
return Math.random() < .5? c : c.toUpperCase();
}).join('');
}
If anyone has suggestions for improving this further - please comment or edit this part of the answer
Well, based on Joel's answer…
myString.toLowerCase().split('').map(function(c){
return Math.random() < .5? c : c.toUpperCase();
}).join('');
Is there an alternative, faster method of returning the position/index of part of an array within another array (where multiple values match)? It's called a lot within my pathfinding algorithm so could do with being as fast as possible.
My current function is:
// Haystack can be e.g. [[0,1,278.9],[4,4,22.1212]]
function coordinate_location_in_array(needle,haystack){
for(n in haystack){
if(haystack[n][0]==needle[0] && haystack[n][1]==needle[1]) return n;
}
return false;
}
// Needle of [0,1]: returns 0
// Needle of [4,4]: returns 1
// Needle of [6,7]: returns false
Edit:
I've been messing around a bit and come up with a (rather ghastly) string manipulation-based method (thereby avoiding the costly for loop). I think it's still slightly slower. Could anybody benchmark these methods?
function coordinate_location_in_array(needle,haystack) {
var str1 = ':' + haystack.join(':');
var str2 = str1.replace(':'+needle[0]+','+needle[1],'*').split('*')[0];
if(str2.length == str1.length) return false;
var preceedingElements = str2.match(/:/g);
return preceedingElements!=null?preceedingElements.length:0;
}
Perhaps with some improvements this second method might provide some performance gain?
Edit 2:
Bench marked all 3 described methods using jsperf.com (initial method is fastest):
http://jsperf.com/finding-matched-array-within-array/3
Edit 3:
Just replaced the for(..in..) loop with a for(..;..;..) loop (since I know that the haystack array will never have "gaps") and performance seems to have significantly improved:
function coordinate_location_in_array(needle,haystack){
for(var n=0;n<haystack.length;n++){
if(haystack[n][0]==needle[0] && haystack[n][1]==needle[1]) return n;
}
return false;
}
I've updated the jsperf page to include this latest method.
If the "haystack" isn't sorted then there isn't a way to make it faster. Not knowing how the elements in a collection are ordered makes finding something out of it linear by nature, because you just have to check each thing.
If you are using this function over the same "haystack" over and over, you could sort the collection, and use the sorting to make it quicker to find the "needle" (look up different sorting and search algorithms to find one that fits your need best, such as using binary search to find the "needle" after haystack is sorted.)
i don't know if its faster, but you can do something like:
[1,2,3,4].slice(0,2).toString() == [1,2].toString()
in your case it would be:
function coordinate_location_in_array(needle,haystack){
for(n in haystack){
if(haystack[n].slice(0,2).toString() == needle.toString()) return n
}
return false;
}
Also found this post, which covers comparison of JS arrays: compare-two-arrays-javascript-associative
Cheers
Laidback
Using a for(..;..;..) loop rather than a for(..in..) loop made the biggest difference.
(See Edit 3 at the end of the question)
Seems to me this is just a substring search but with numbers instead of characters being the components of the string. As such, Boyer-Moore could be applicable, especially if your needles and haystacks get big.