See if the end of strings match - javascript

I have this exercise: Check if a string (first argument, str) ends with the given target string (second argument, target) without using the method endsWith() or any other method. What's wrong with my code?
function confirmEnding(str, target) {
for (var i = 1; i <= target.length; i++) {
val = false
if (str[str.length - i] === target[target.length - i]) {
val = true;
}
return val;
}
}
confirmEnding("Bastian", "n");
//original code from post above:
console.log(confirmEnding("Bastian", "n")); //added to provide working example

In your original code there are a few problems:
Will address them inline:
function confirmEnding(str, target) {
// using a for loop to iterate over the target string's length
for (var i = 1; i <= target.length; i++) {
//setting up a variable that says false
val = false
//trying to compare the individual characters
if (str[str.length - i] === target[target.length - i]) {
//so what happens here:
//when the two match this will set val to true
//but every time the loop is run is will reset to false.
val = true;
}
//the return value is in the loop, so the loop will run once
return val;
}
}
confirmEnding("Bastian", "n");
With the above script you have no way of knowing if all the characters match. If the last character matches it will return true, even if the other characters don't match.
string: Bastian target: irr
Will return true in the logic of your loop.
Take a look at the code below and the comments in it!
function confirmEnding(str, target) {
//get the length of the target string
const targetLength = target.length;
//set up an empty string
let endstr = "";
for (let i = 1; i <= targetLength; i++)
{
//start at 1 since str.length-1 is last character
//fill the empty string with the last characters of str
endstr = str[str.length-i] + endstr;
}
//compare and return
return target === endstr;
}
console.log(confirmEnding("Bastian", "ian")); //TRUE
console.log(confirmEnding("Bastian", "in")); //FALSE

The problem in your current code is that the variable for the result is initialised inside the loop.
So it actually only returns true/false depending on the last character it compares.
Which would be the first character of the target string.
What you can do is get out of that loop as soon a difference is found.
And additional, also check if the string isn't smaller than the target, because then it would be false anyway.
F.e.
function confirmEnding(str, target) {
if(str.length < target.length)
return false;
for (var i = 1; i <= target.length; i++) {
if (str[str.length - i] !== target[target.length - i]) {
return false;
}
}
return true;
}
console.log(confirmEnding("Bastian", "ian"));
console.log(confirmEnding("Bastian", "ion"));
console.log(confirmEnding("an", "ian"));

const confirmEnding = (str,target) => str.slice(-target.length) === target;
console.log(confirmEnding('peace','ace')); // true
console.log(confirmEnding('devotion','tio')); // false
console.log(confirmEnding('faith and love','nd love')); // true
we know that "slice" take 2 arguments: [ index | how many items ]
more so, a negative index would start extracting characters from the end of a string
we can use this to our advantage by utilizing the "length" property from "target" to set the "index" on the "slice" method
let's use "peace" as our example to breakdown the code:
('peace','e') => str.slice(-1) === 'e';
str.slice(-1) --> return the last character 'e' from "peace"
('peace','e') => 'e' === 'e'; --> "true"

Related

Checking if str1 can be re-arranged as str2 wth JavaScript

There are two strings called str1 and str2 and I'm trying to check if str1 can be re-arranged as str2.
FOR EXAMPLE: lets say str1 = "aabbcamaomsccdd" and str2="commas".
Is it possible to write the word "commas" out of "str1"
function scramble(str1, str2) {
let arr=[];
let str1arr = str1.split("");
let str2arr = str2.split("");
let j=0;
for(let i=0; i<str1.length; i++){
if(str1arr[i]==str2arr[j]){
arr.push(str1arr[i]);
str1arr=str1arr.splice(i,1);
j++;
i=0;
}
}if(arr.toString()===str2arr.toString()){
return true;
}else{
return false;
}
}
What I tried basically if str1arr[i]==str2arr[j] it will put the str1arr[i] value on a new array called arr and at the end it will compare str2 and the arr and return True or False.
The reason why I used str1arr=str1arr.splice(i,1); to delete the i after the match is because the for loop is reseting it self to check from the "i=0" each time i and j matches and that i would match with other duplicate letters (I hope thats what it does atleast :D).
It is an internet question and im not passing the tests. I only pass if the result is FALSE.
I want to know what I'm doing and thinking wrong here. Its not performance efficent too so any comment on that would be great too.
You could take arrays and sort them and check each character of the second string/array against the first one.
function compare([...a], [...b]) {
a.sort();
return b.sort().every((i => v => {
while (i < a.length && a[i] !== v) i++;
return a[i++] === v;
})(0));
}
console.log(compare("aabbcamaomsccdd", "commas")); // true
console.log(compare("aabbcamaomccdd", "commas")); // false
You should just check that both strings contain the same chars like so:
function scramble(str1, str2) {
var s1 = str1.split('');
var s2 = str2.split('');
var i;
for (i = 0; i < s2.length; i++) {
const idx = s1.indexOf(s2[i]);
if (idx === -1) {
return false;
}
s1.splice(idx, 1);
}
return s1.length === 0;
}
console.log(scramble('xcab1c', 'abxcc1'));
You could count the frequency of each character in your first string. Below I have used .reduce() to build an object with key-value pairs, where the key represents a character from your s1 string and the value is how many times it appears. You can then loop through the characters in s2 and check that every character appears in the frequency map. When you see a character you can subtract one from the value from the frequency object to signify that the character has been "used". If the .every() callback returns a falsy value (such as 0 for the value), then the result will be false, as your string can't be re-arranged:
const scramble = (s1, s2) => {
const s1Freq = [...s1].reduce((o, c) => ({...o, [c]: (o[c] || 0) +1}), {});
return [...s2].every(char => s1Freq[char]--);
}
console.log(scramble("aabbcamaomsccdd", "commas")); // true
console.log(scramble("abc321", "123")); // true
console.log(scramble("a3b2c11", "1231")); // true
console.log(scramble("a", "a")); // true
console.log(scramble("xyz", "xyt")); // false

How to build a function that searches for string occurrences?

I need help Writing a function subLength() that takes 2 parameters, a string and a single character. The function should search the string for the two occurrences of the character and return the length between them including the 2 characters. If there are less than 2 or more than 2 occurrences of the character the function should return 0. How can I solve this problem using loops?
subLength('Saturday', 'a'); // returns 6
subLength('summer', 'm'); // returns 2
subLength('digitize', 'i'); // returns 0
subLength('cheesecake', 'k'); // returns 0
Here I loop through the characters of the string to find each value that is the char.
if the length isn't 2, return 0.
using slice, get only the characters within the two found indexs and get that length adding one to fix the offset
const subLength = (str, char) => {
let strChars = str.toLowerCase().split(""),
found = [],
length = 0;
strChars.forEach((val, index) => {
if (val === char) {
found.push(index);
}
});
if (found.length != 2) {
return length;
}
return str.slice(found[0], found[1]).length + 1;
}
console.log(subLength('Saturday', 'a')); // returns 6
console.log(subLength('summer', 'm')); // returns 2
console.log(subLength('digitize', 'i')); // returns 0
console.log(subLength('cheesecake', 'k')); // returns 0
You can try this logic:
Loop over string and count number of occurance
if count is 2,
Create a regex to capture the string in between.
Return its length
Else return 0
function subLength(str, char) {
let length = 0;
const occuranceCount = Array
.from(str)
.filter((c) => c.toLowerCase() === char.toLowerCase())
.length
if (occuranceCount === 2) {
const regex = new RegExp(`${char}(.*)${char}`)
length = str.match(regex)[0].length
}
console.log(length)
return length;
}
subLength('Saturday', 'a'); // returns 6
subLength('summer', 'm'); // returns 2
subLength('digitize', 'i'); // returns 0
subLength('cheesecake', 'k'); // returns 0
Using just for loop:
function subLength(str, char) {
let count = 0;
let initPosition;
let lastPosition;
for (let i = 0; i < str.length; i++) {
if (str[i] === char) {
count++
if (count > 2) {
return 0;
}
if (initPosition === undefined) {
initPosition = i
} else {
lastPosition = i+1
}
}
}
return count < 2 ? 0 : lastPosition - initPosition;
}
console.log(subLength('Saturday', 'a')); // returns 6
console.log(subLength('summer', 'm')); // returns 2
console.log(subLength('digitize', 'i')); // returns 0
console.log(subLength('cheesecake', 'k')); // returns 0
I too am going through the Codecademy course where this question came up which led me to this post.
Using the RegExp solution provided by #Rajesh (thank you!!) I started to break it down to better understand what was going on and making notes/comments because I am still pretty new and haven't used or been exposed to some of these things.
At the end of it all I thought I'd share what I ended up with in case anyone found it helpful.
function subLength(str, char) {
// Outputting to the console what we are looking for given the value of the string and character from the test cases at the end of this script.
console.log(`Showing the subLength for the string: "${str}" between "${char}" and "${char}" including the "${char}" positions.`);
// create the length variable which will be returned by the function
let length = 0;
// ** Search the string for the two occurrences of the character and count them. Then assign the result to the occurrenceCount variable for use in the if else statement.
// The "Array" class is a global object that is used in the construction off arrays.
// The Array.from() static method creates a new, shallow-copied Array instance from an array-like or iterable object.
// The Array.filter() method creates a new array with all elements that pass the test implemented by the provided function. The "c" represents each element of the array/string which is then compared to the char variable. if it is a match it gets added to the Array. We use .toLowerCase on both to ensure case compatibility.
// Appending the Array with ".length" assigns occurrenceCount the numeric value of the array's length rather than the array of characters.
const occurrenceCount = Array.from(str).filter((c) => c.toLowerCase() === char.toLowerCase());
console.log(' The contents of the occurrenceCountArray = ' + occurrenceCount);
console.log(' The character occurrence count = ' + occurrenceCount.length);
// if the string has two occurrences : return the length between them including the two characters : else the string has less than 2 or more than 2 characters : return 0.
if (occurrenceCount.length === 2) {
// The RegExp object is used for matching text with a pattern. The "(.*)" in between the ${char}'s will match and capture as much as possible aka greedy match. "()" = capture anything matched. (" = start of group. "." = match any character. "*" = Greedy match that matches everything in place of the "*". ")" = end of group.
const regex = new RegExp(`${char}(.*)${char}`);
// log to console the pattern being matched
console.log(` regex pattern to find = ${regex}`);
// log to the console the [0] = index 0 pattern that was captured from the string using str.match(regex)[0]
console.log(` regex output = ${str.match(regex)[0]}`);
// Use".length" to count the number of characters in the regex string at index 0 of the regex array and assign that value to the length variable.
length = str.match(regex)[0].length;
// Output the results to the console
console.log(` The distance from "${char}" to "${char}" (including the "${char}" positions) in the string: ${str} = ${length}\n`);
// return the length value
return length;
} else {
// Output the results to the console
console.log(` The string either has too many or too few occurrences.\n The subLength = ${length}\n`);
// return the length value
return length;
}
}
// test cases
subLength('Saturday', 'a'); // returns 6
subLength('summer', 'm'); // returns 2
subLength('digitize', 'i'); // returns 0
subLength('cheesecake', 'k'); // returns 0
The answer I am getting is this:
const subLength = (str, char) => {
let charCount = 0;
let len = -1;
for (let i=0; i<str.length; i++) {
if (str[i] == char) {
charCount++;
if (charCount > 2) {
return 0;
}
if (len == -1) {
len = i;
} else {
len = i - len + 1
}
}
}
if (charCount < 2) {
return 0;
}
return len;
};
It is better to try yourself a solution first. It is a very bad practice to just ask a solution for your homework!!!
Even if the solution can be JUST a few lines of code i wrote for you with commments a working solution :
const subLength = (str,char) => {
// create an empty array
const strarr = [];
// push string into array
strarr.push(str);
//initiate a count variable
let count = 0;
// WRITE YOUR REGULAR EXPRESSION
// Using the regular expression constructor - new RegExp("ab{2}", "g") .
const regString = `[${char}]`;
const regex = new RegExp(regString, "g");
// iterate through the string array to
for (let i = 0; i < strarr.length; i++) {
// calculate how many time the character occurs
count = (strarr[i].match(regex) || []).length;
};
// check with if condition
//if count is 2
if (count === 2) {
// calculate the index of first ocurrance of the string
first = str.indexOf(char);
// calculate the index of second ocurrance of the string
second = str.lastIndexOf(char);
// calculate the distance between them
return second - first + 1;
// if count is greater than two return 0
}
else if (count > 2) {
return count = 0;
}
// if count is less than two return 0
else if (count < 2) {
return 0;
}
};
console.log(subLength("iiiiliiile","l"));
I just answered this problem in codeAcademy and this is the solution that I came up with, just using if-statements and string.indexOf
const subLength = (strng, char) => {
let firstIndex = strng.indexOf(char);
let secondIndex = strng.indexOf(char, (firstIndex + 1));
let thirdIndex = strng.indexOf(char, (secondIndex + 1));
if (firstIndex === -1){
return 0
} else if (secondIndex === -1){
return 0
} else if (thirdIndex === -1 ){
return (secondIndex - firstIndex + 1)
} else {
return 0
};
};

Comparing values between two arrays

I'm trying to set up a function that checks if a word or a text is a palindrome. To do that, it splits the text so that every letter is an element of a new array, it takes rid of the white spaces and it makes the reverse array.
Then it checks if every element of the two arrays, at the same positions, are equal. If not it returns false, if yes it returns true.
Here the function:
function palindrome(str) {
var low = str.toLowerCase();
var newArray = low.split("");
var noSpace = newArray.filter(function(val) {
return val !== " ";
});
var reverse = noSpace.reverse();
function check (a, b) {
console.log(`checking '${a}' against '${b}'`);
var partial;
var result = 1;
for (var i = 0; i < a.length; i++) {
console.log(`comparing '${a[i]}' and '${b[i]}'`);
if (a[i] !== b[i]) {
result = 0;
} else {
partial = 1;
result *= partial;
}
}
return result;
}
var result = check(noSpace, reverse);
if (result == 1) {
return true;
} else {
return false;
}
}
palindrome("r y e");
I don't know what's wrong but it seems that the function keeps on returning a true value no matter what word or text I pass to the function. What is wrong with that?
Your issue seems to be because reverse() changes the actual array as well. So doing
var reverse = noSpace.reverse();
Will reverse noSpace and assign a reference to it on the variable reverse. That is, both arrays will be the same (reversed) array.
To bypass that, I've used .slice() to create a copy of the original array, and then called .reverse() on that new array, ridding you of any conflicts.
Here's a working snippet of what it looks like:
function palindrome(str) {
var str_array = str.toLowerCase().split("");
var no_space = str_array.filter(function(val) {
return val !== " ";
});
// By applying '.slice()', we create a new array
// reference which can then be reversed and assigned
// to the 'reverse' variable
var reverse = no_space.slice().reverse();
function check(a, b) {
var partial;
var result = 1;
for(var i=0; i < a.length; i++) {
if(a[i] !== b[i]) {
// We don't need to keep
// comparing the two, it
// already failed
return 0;
} else {
// I've kept this part even though
// I don't really know what it is
// intended for
partial = 1;
result *= partial;
}
}
return result;
}
return check(no_space, reverse) === 1;
}
console.log(palindrome("a b a"));
console.log(palindrome("r y e"));
The way you have coded for palindrome is way too complicated.
But there is one problem with your code: when you do a reverse() it changes the original array as well.
So you will need to make sure that you copy it via slice().
Also you can directly send a boolean result rather than doing a 1 and 0.
At result *= partial;, 1 * 1 will always equal 1
I didn't correct your code, but here is a optimized solution for you.
function palindrom(string) {
var arr = string.split("");
var lengthToCheck = Math.floor(arr.length / 2);
for (var i = 0; i < lengthToCheck; i++) {
if (arr[i] != arr[arr.length - (1 + i)]) {
return false;
}
}
return true;
}
First I split the array after every charater of the passed String. After that I get the half of the length of the array as it's enough to check just one half.
With the for-loop I compare the first half with the second half. As soon as I found two characters that do not match I return false. In case the whole first half matches the second half of the array, the for-loop will be completed and after that true will be returned.
What's actually happening is .reverse() reverses an array in place, it then stores a reference to that array which is not what you're calling in your check() method.
Simple fix would be to change your if statement:
if (a[i] !== b.reverse()[i])

Javascript How to identify if all elements of one array are present in another

I need to create a function to check if all the letters in the second string of a two string array are present in the first string. The function I wrote seems to work for most of the examples I tried with it but ["hello" , "hey"] returns true despite there not being a y in hello and I don't understand why.
Here's my code:
function mutation(arr) {
arr[0] =arr[0].toUpperCase().split("");
arr[1] =arr[1].toUpperCase().split("");
for(i=0;i<arr[1].length;i++){
if(arr[0].indexOf(arr[1][i])>=0){
return true;
} else {return false;}}}
mutation(["hello", "Hey"]);
You are returning true even if one character is matched ,Try below code it checks if all characters are present or not
function mutation(arr) {
arr[0] = arr[0].toUpperCase().split("");
arr[1] = arr[1].toUpperCase().split("");
var count = 0;
for (i = 0; i < arr[1].length; i++) {
if (arr[0].indexOf(arr[1][i]) >= 0) {
count++;
}
}
return count === arr[1].length
}
mutation(["hello", "Hey"]);
here is one more efficient solution, it works only for lowercase letters.
(function(){
function charCode(str, i){
return str.charCodeAt(i) - 97;
}
function isMutation(a,b){
const aArr = new Uint8Array(26);
const bArr = new Uint8Array(26);
let i=0;
let index = 0;
while(i<a.length){
++aArr[charCode(a, i)];
++i;
}
i = 0;
while(i<b.length){
++bArr[charCode(b, i)];
++i;
}
i = 0;
while(i < 26){
if(!(aArr[i]===0 && bArr[i]===0 || aArr[i]>0 && bArr[i]>0)){
return false
}
++i;
}
return true;
}
console.assert(isMutation('hello', 'oleh') === true);
console.assert(isMutation('hello', 'hey') === false);
})();
you can also compare sum of uniq chars in the both arrays, but in this case you have to add each letters only once.
I would recommend using one of the code solutions suggested by user georg at Remove Duplicates from JavaScript Array.
For example, the function below could be used to sort each array (arr[0] and arr[1]) and remove duplicates.
Credit to user georg at the link above.
function uniq(a) {
return a.sort().filter(function(item, pos, ary) {
return !pos || item != ary[pos - 1];
})
}
Once you have sorted/removed duplicates, you can test to see if the two returned strings are equal or not.
Hello => EHLO, and Hey => EHY
EHLO !== EHY

Comparing a reversed string to it's original without using .reverse() method

I'm attempting to compare an original string argument with its reverse. In essence, this function is supposed to verify whether or not a given string is a palindrome. Key points:
String needs to be converted to all lowercase, which I did.
String needs to consist of only alphanumeric characters, which I did.
When compared, the original string and formatted string must match. If they do, the boolean value of true gets returned, otherwise false does.
Here is the source code: JS Fiddle | Alternatively, code is below:
function palindrome(str) {
var reverseString;
var temp;
var formatted;
// make sure input gets converted to lowercase
temp = str.toLowerCase();
// make sure all non-alphanumeric characters get removed
// once converted to lowercase, ensure that all special characters and digits are stripped from the string
formatted = temp.replace(/[^A-Za-z]/g, '');
// now we need to compare two strings: the raw input vs the string in reverse
for (i = formatted.length -1; i >= 0; i--) {
reverseString += formatted[i];
}
if (reverseString === str) {
return true;
}
return false;
}
palindrome("123$EYE");
function palindrome(str) {
var reverseString=""; // initialize every string to ""
var temp="";
var formatted="";
temp = str.toLowerCase();
formatted = temp.replace(/[^A-Za-z0-9]/g, ''); // I added 0-9 in your regex to have numbers in your string
for (i = formatted.length -1; i >= 0; i--) {
reverseString += formatted[i];
}
if (reverseString === formatted) { // change str to formatted
return true;
}
return false;
}
var isPal = palindrome("123$EYE");
alert(isPal); // try it on `alert` if it is true or false
Your code is ok. But you have some flaws. You should initialize your String to "" so it will not have a value of undefined. The one you put on your if statement is str which is your original String word, you should put your formatted String because that is the one you removed the special characters.
Why reverse and compare? You just need to compare the characters of the same position from the head and from the tail. First str[0] and str[length - 1], then str[1] and str[length - 2], and so on. Till you reach the middle, or any comparison fails.
function isPalindrome(str) {
var len = str.length
for (var i = 0; i < Math.ceil(len/2); i++) {
if (str[i] !== str[len - 1 - i]) {
// or add more comparison rules here
return false
}
}
return true
}
isPalindrome('1') // true
isPalindrome('121') // true
isPalindrome('1221') // true
isPalindrome('1211') // false
alphanumeric characters?
function palindrome(str) {
var temp;
temp = str.toLowerCase();
temp = temp.replace(/[^A-Za-z0-9]/g, '');
console.log(temp);
for (let a = 0, b = temp.length - 1; b > a; a++, b--) {
if (temp.charAt(a) !== temp.charAt(b))
return false;
}
return true;
}
You didn't initialize reverseString so it will be undefined at the beginning. Adding a character 'a' to undefined returns a string 'undefineda', instead of 'a' which you probably expect.
Change your code to
var reverseString = '';
and it'll work
Here is an elegant way to reverse the text:
var rev = temp.split('').reverse().join(''); // reverse
check out fiddle:
function palindrome(str)
{
var temp = str.toLowerCase() // converted to lowercase
.replace(/[^A-Za-z]/g, ''); // non-alphanumeric characters removed
var rev = temp.split('').reverse().join(''); // reverse
console.log(temp, ' === ', rev, ' is ', temp === rev);
if(temp === rev)
{
return true;
}
return false;
}
var out = palindrome("123$EYE");
document.getElementById('divOutput').innerHTML = out;
<div id="divOutput"></div>

Categories

Resources