Javascript: Palindrome function undefined? - javascript

I have been working on a palindrome function (will check if word is spelled the same forward and backwards):
var palinDromes = function(palMap) {
palMap.split(" ").map(function(word) {
var palCheck = (word.toLowerCase() === word.toLowerCase().split("").reverse().join(""));
return palCheck;
});
};
console.log(palinDromes('Hannah speaks English and Malayalam'));
But the output is always undefined. I believe the issue is in the first step, something involving the console.log(palinDrome(...)); transition to palMap, but I'm not sure what exactly.
The issue might also be that I am not returning palCheck correctly at the end of the function?

var palinDromes = function(palMap) {
return palMap.split(" ").map(function(word) {
var palCheck = (word.toLowerCase() === word.toLowerCase().split("").reverse().join(""));
return palCheck;
});
};
console.log(palinDromes('Hannah speaks English and Malayalam'));
EDIT: I added a return before palMap.split(" ").map(function(word) { ...

Related

How to find whole substring in string?

I have a string and I have to check if that string contains defined substring I need to do some work and otherwise, I should return some error.
I have the following code:
function isContains(myString) {
let subString = 'test1234';
if(myString.includes(subString)) {
// to do some work
} else {
// return some error.
}
}
but the problem is if myString = 'my-string-test1-rrr' its condition return true.
How can I get true only in case when the whole subString was included in myString?
Use indexOf() instead.
function isContains(myString) {
let subString = 'test1234';
if(myString.indexOf(subString) > -1) {
// to do some work
} else {
// return some error.
}
}
you can use regex to check if that value is present are not;
example 1
without containing the specific string
var test = 'my-string-test1-rrr';
console.log(' test --- ', test.match(/test1234/g))
example 2
contains the specific string
var test = 'my-string-test1234-rrr';
console.log(' test --- ', test.match(/test1234/g))
It is highly recommended to use includes() over indexOf() and further indexOf returns the index of the occurrence where you would prefer an immediate answer - false / true if that substring is found inside the searched string.
Your function does exactly what you are asking. I would suggest to isolate the retrieval of this function and make it purer like so, then when you have the return boolean value you could utilize it after to run whatever logic you wish. This way you keep this function pure and separate your concerns better.
I also believe it would be easier for you to debug your issue if you isolate this functions like In the example I provided.
function isContains(myString) {
let subString = 'test1234';
let isContains = false;
if(myString.includes(subString)) {
isContains = true;
} else {
isContains = false;
}
return isContains;
}
You could use it like so in a later phase in your code:
const myString = 'my-string-test1-rrr';
let shouldRunOtherLogic = isContains(myString);
if (shouldRunOtherLogic) {
// to do some work
} else {
// return some error.
}
Hope I could help, if there's anything further you may need feel free to let me know.

Confirm the ending of a string without using endsWith()

Aim:
Check if a string (first argument, str) ends with the given target string (second argument, target). This challenge can be solved with the .endsWith() method but I don't want to use it.
A workable solution:
function confirmEnding(str, target) {
return str.slice(str.length - target.length) === target
}
console.log(confirmEnding("Open sesame", "game")); // false
Above is the "SOLUTION". I got frustrated after seeing how simple it was!
However, although my code was very complicated, I still want it to work out.
Below is my code:
function confirmEnding(str, target){
let newStr = str.split('').reverse()
let newTarget = target.split('').reverse()
function matching (newStr, newTarget){
for (let i = 0; i < newTarget.length ; i++){
return (newTarget[i] === newStr[i]) ? true : false
}
}
}
console.log(confirmEnding("Open sesame", "game"))
It print true, but I expect it to be false.
It is very messy; I want to make the loop to continue on and stop when it hits the false.. How can I do that?
Also, I'm not quite sure where and what "return code" should be added at the end of the function.
Here are the issues with your code:
The nested function isn't necessary
The loop should only return false if it finds a difference
If the loop completes without finding a difference, then you can return true
function confirmEnding(str, target){
let newStr = str.split('').reverse()
let newTarget = target.split('').reverse()
for (let i = 0; i < newTarget.length ; i++) {
if (newTarget[i] !== newStr[i]) {
return false;
}
}
return true;
}
console.log(confirmEnding("Open sesame", "game"))
console.log(confirmEnding("Open sesame", "same"))
A more efficient way to solve the problem is with a regex:
function confirmEnding(str, target) {
return new RegExp(`${target}$`).test(str);
}
console.log(confirmEnding("Open sesame", "game"))
console.log(confirmEnding("Open sesame", "same"))
can you use regex? if you know what the ending might look like you can use regex with indexOf to verify. this assumes you are using javascript
Try this out. The code I use here made things more intuitive to me.
function confirmEnding(str, target) {
let result = str.slice(-target.length);
if (result === target) {
return true} else {
return false}
}

input box asking for two specific words

I'm new to this, so I hope I can explain well enough what my problem is.
I've got a quiz and for an answer I created an input box. To get to another link you have to put two words in there but the order should not matter aka. it shouldn't matter if you write down "word1 word2" or "word2 word1", there should be only one rule: both words should be mentioned.
Is that possible?
My code so far:
function checkText()
{
var textwunf_1 = document.getElementById("wunf").value;
if(textwunf_1.toLowerCase() == "word1" && "word2"){
window.open("URL","_self");
}
else{
xxx
}
}
It does not work.
Before I only wanted to check if one word is used, like that:
var textwunf_2 = 'word1';
function checkText()
{
var textwunf_1 = document.getElementById("wunf").value;
if(textwunf_1.toLowerCase().indexOf(textwunf_2) == -1){
xxx
}
else{
window.open("URL","_self");
}
}
This worked but I can't use it for two words, because if I write
var textwunf_2 = 'word1 word2';
the order can't be 'word2 word1'...
Is there a solution to my problem?
Hopefully anyone can understand and help me, thank you!
Based on this commentary from the OP:
if the user types 3 words and two of them match with the answer, it should be also okay! even better if even 3 words or more are possible, as long as the user puts my two words in it..
You can check if both words are whitin the text using two conditions on the if:
textwunf_1.toLowerCase().indexOf("word1") >= 0
AND
textwunf_1.toLowerCase().indexOf("word2") >= 0
Try with the next code:
var textwunf_2 = 'word1';
var textwunf_3 = 'word2';
function checkText()
{
var textwunf_1 = document.getElementById("wunf").value;
if ((textwunf_1.toLowerCase().indexOf(textwunf_2) >= 0) &&
(textwunf_1.toLowerCase().indexOf(textwunf_3) >= 0))
{
window.open("URL","_self");
}
else
{
// xxx
}
}
Another approach:
var words = ["word1", "word2"];
function CheckWords() {
var inputWords = document.getElementById("wunf").value.split(' ');
var allWordsFound = true;
if (inputWords.length !== words.length) { return false; }
inputWords.forEach(function(word) {
if (words.indexOf(word.toLowerCase()) === -1) {
allWordsFound = false;
return;
}
});
return allWordsFound;
}
console.log(CheckWords());
I am creating a function that receive the text and check if include the answers(xx and yy), it doesn't matter the order. The ans list, can have 1,2 or more words, it will work.
let ans = ['xx','yy'];
function check(text){
text = text.toLowerCase();
let counter = 0;
ans.forEach((x) => {text.includes(x) && counter++ })
return counter === ans.length
}
console.log(check("aa bb")) // false
console.log(check("xx bb")) // false
console.log(check("aa yy")) // false
console.log(check("xx yy")) // true
console.log(check("yy xx")) // true

Run one value through multiple functions (Javascript)

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.

Alternative solution to underscore.js

I have created a game that is based on a grid being populated with words
In my code I have a small bit of underscore.js that helps my words fit in the space available in the grid without breaching the grids barriers.
I understand that it is very powerful java script and don't personally have a problem with it. But my team manager would like to get rid of it for some jQuery that will provide the same solution as there is only one function and would save me having a whole library. How I would replace this with some jQuery?
function getWordToFitIn(spaceAvail, wordlist) {
var foundIndex = -1;
var answer = _.find(wordlist, function (word, index) {
if (word.length <= spaceAvail) {
foundIndex = index;
return true;
}
});
if (foundIndex == -1) {
answer = getXSpaces(spaceAvail);
_.find(wordlist, function (word, index) {
if (word[0] == " ") {
foundIndex = index;
return true;
}
});
}
if (foundIndex != -1) {
wordlist.splice(foundIndex, 1);
}
return answer;
}
As far as I can see, the only underscore method youre using is _.find. But I don’t think you are using it as it was intended. It looks like you are simply looping and returning true when a criteria is met.
You can use the native forEach if you don’t have legacy support, or use a shim. Or you can use the jQuery.each method.
The first loop could probably (I’m not 100% sure about the answer variable) be written like this:
var answer;
$.each(wordlist, function(index, word) {
if (word.length <= spaceAvail) {
foundIndex = index;
answer = word;
return false; // stops the loop
}
});
And the second one:
$.each(wordlist, function (index, word) {
if (word[0] == " ") {
foundIndex = index;
return false;
}
});

Categories

Resources