Printing elements that don't satisfy condition - javascript

I'm trying to complete a HackerRank challenge that involves printing a list of elements of an array starting with all the vowels then all the consonants but I'm having trouble with that.
function vowelsAndConsonants(s) {
var str = s;
var arr = str.split("");
var i;
var vow = ["a","e","i","o","u","y"];
var con = ['b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','z']
for (i = 0; i < arr.length; i++) {
for (var j = 0; j< vow.length; j++){
if (arr[i] === vow[j]){
console.log(arr[i])
}
}
}
}
This is what I get from the code above, but I can't print the consonants. The input string is "javascriptloops"
a
a
i
o
o
I also tried this
function vowelsAndConsonants(s) {
var str = s;
var arr = str.split("");
var i;
var vow = ["a","e","i","o","u","y"];
var con = ['b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','z']
for (i = 0; i < arr.length; i++) {
for (var j = 0; j< vow.length; j++){
if (arr[i] === vow[j]){
console.log(arr[i])
break;
}
}
for (var j = 0; j< con.length; j++){
if (arr[i] === con[j]){
console.log(arr[i])
}
}
}
}
But here's what I had
j
a
v
a
s
c
r
i
p
t
l
o
o
p
s

An easy solution would be looping through twice:
function vowelsAndConsonants(s) {
let vowels = ["a", "e", "i", "o", "u"];
for(let v of s) {
if(vowels.includes(v))
console.log(v);
}
for(let v of s) {
if(!vowels.includes(v))
console.log(v);
}
}

It's a good idea to define the smaller subset (vowels) and treat the rest of the letters of the alphabet as consonants.
Also, naming your variables goes a long way in readability
function vowelsAndConsonants(s) {
var letters = s.split("");
const vowels = ["a", "e", "i", "o", "u", "y"];
for (const letter of letters) { // we are cycling through the letters to find all vowels
for (const vowel of vowels) { // now we are cycling through the list of vowels
if (letter === vowel) { // if we found a vowel in the vowel list, print it and stop searching for other vowels (break)
console.log(letter);
break;
}
}
}
// Searching for consonants is trickier
for (const letter of letters) { // we cycle again through the letters
let consonant = true; // we assume that the letter is consonant until it's proven otherwise
for (const vowel of vowels) { // cycling through the list of vowels
if (letter === vowel) { // if we found that the letter is vowel
consonant = false; // we set the flag to false
break; // and stop searching more as we know already that it is a vowel
}
}
if (consonant === true) { // if after cycling we realized that this is a consonant, and not a vowel - print it
console.log(letter)
}
}
}
vowelsAndConsonants("normal");

there is a solution, you can take a look
function vowelsAndConsonants(s) {
var str = s;
var arr = str.split("");
var vow = ["a","e","i","o","u","y"];
const ordered = arr.reduce( (res, letter) => {
if (vow.includes(letter)) {
return {...res, vow: [...res.vow, letter]}
}
return {...res, con: [...res.con, letter]}
}, { con: [], vow: []});
return ordered.vow.join('') + ordered.con.join('');
}

Your outer loop needs to run twice.
This solution also uses for ... in loops and array.includes(), which is a little cleaner than nesting standard for loops.
const vowelsAndConsonants = s => {
const vow = ['a','e','i','o','u','y'];
for (const c of s)
if (vow.includes(c))
console.log(c)
for (const c of s)
if (!vow.includes(c))
console.log(c)
}
vowelsAndConsonants('javascriptloops')

You can use filter() instead of loops:
var vow = ['a','e','i','o','u','y'].join('');
var str = 'javascriptloops'.split('');
console.log(str.filter(x => vow.includes(x))); // vowels
console.log(str.filter(x => !vow.includes(x))); // consonants (not vowels)

const f = s => {
const isVowel = char => ['a', 'e', 'i', 'o', 'u'].includes(char);
const letters = s.split('');
const consonants = letters.reduce((result, letter) => {
if (isVowel(letter)) console.log(letter);
else result.push(letter);
return result;
}, []);
consonants.forEach(c => console.log(c))
}
f('javascriptloops');

Related

Why is my nested loop only finding one duplicate character in a string?

My apologies if this is a duplicate, I couldn't find an answer after searching for a while on Stackoverflow.
I am trying to use a nested loop to find any duplicate characters in a string.
So far, all I can manage to do is to find one duplicate the string.
For example, when I try the string "aabbcde", the function returns ['a', 'a'], whereas I was expecting ['a', 'a', 'b', 'b'].
I obviously have an error in my code, can anybody help point me towards what it could be?
const myStr = "aabbcde";
function duplicateCount(text){
const duplicates = [];
for (let i = 0; i < text.length; i++) {
for (let j = 0; j < text[i].length; j++) {
if (text[i] === text[j]) {
duplicates.push(text[i]);
}
}
}
return duplicates;
}
duplicateCount(myStr);
It should be something like this.
issues in this loop for (let j = 0; j < text[i].length; j++)
const myStr = "aabbcde";
function duplicateCount(text){
const duplicates = [];
for (let i = 0; i < text.length; i++) {
for (let j = i+1; j < text.length; j++) {
if (text[i] === text[j]) {
duplicates.push(text[i]);
}
}
}
return duplicates;
}
console.log(duplicateCount(myStr));
Using nested loop will make it very hard to do it,we can use a Object to store the appear count,and then filter the count
const myStr1 = "aabbcde";
const myStr2 = "ffeddbaa";
const duplicateCount = str => {
let map = {}
for(c of str){
map[c] = (map[c]??0) + 1
}
let result = []
for(m in map){
if(map[m] <= 1){
continue
}
result.push(...Array(map[m]).fill(m))
}
return result
}
console.log(duplicateCount(myStr1))
console.log(duplicateCount(myStr2))
You can simply achieve the result you're looking for by creating an object map of the string (meaning each key of the object will be each unique character of the string and their associated values will be the number of times each character is repeated in the string).
After you create an object map of the string, you can loop through the object and check if each value is greater than one or not. If they're you would push that item into a result array by the number of times the character is repeated. Please find my code here:
const myStr = 'aabbcde';
const duplicateCount = (str) => {
const result = [];
const obj = {};
str.split('').map((char) => {
obj[char] = obj[char] + 1 || 1;
});
for (key in obj) {
if (obj[key] > 1) {
for (let i = 0; i < obj[key]; i++) {
result.push(key);
}
}
}
return result;
};
console.log(duplicateCount(myStr));

Multiple of letters count in js

i have a task:
Count the number of letters “a” in text
Count the number of letters “o” in text
Write the result of multiplying the number of letters “a” and “o”.
is it possible to solve this task in a shorter way??
function countString(str, letter) {
let count = 0;
for (let i = 0; i < str.length; i++) {
if (str.charAt(i) == letter) {
count += 1;
}
}
return count;
}
const string = hello my name is Ola.toLowerCase()
const letterToCheck = "o"
const letterToCheckTwo = "a"
const result = countString(string, letterToCheck);
const resultTwo = countString(string, letterToCheckTwo);
const total = result + resultTwo
console.log(total)
With regular expression function match() will output all the matched conditions.
const string = "hello my name is Ola"
const numberOfA = string.match(/a/gi);
const numberOfO = string.match(/o/gi);
console.log(numberOfA.length * numberOfO.length)
you can do something like this using map filter and reduce
const calculate = (string, letters) => letters
.map(l => string.split('').filter(c => c === l).length)
.reduce((res, item) => res * item)
const string = 'hello my name is Ola'.toLowerCase()
console.log(calculate(string, ['a', 'o']))
console.log(calculate(string, ['a', 'o', 'e']))
You can create an object that stores the count of all the characters and then you can compute the product using this object.
const str = "Avacado";
const charsCount = Array.prototype.reduce.call(
str,
(r, ch) => {
const lowerCh = ch.toLowerCase()
r[lowerCh] ??= r[lowerCh] || 0;
r[lowerCh] += 1;
return r;
},
{}
);
console.log(charsCount["o"] * charsCount["a"]);
Note: Array.prototype.reduce is a generic method, so it can be used with a string as well.
There are a few different approaches. In this post I've programmed in a way that allows you to expand to different letters, different amounts of letters, and different strings easily. There may be better approaches if your problem never needs to change.
In your current code, your are traversing the strings twice and counting the occurrences of the letter within them. You could easily pass the function an array and only traverse the string once:
function countString(str, letters) {
//rather than being a character, letter is now an array of characters
let count = 0;
for (let i = 0; i < str.length; i++) {
if (letters.includes(str.charAt(i))) {
count += 1;
}
}
return count;
}
const string = "hello my name is " + Ola.toLowerCase()
const lettersToCheck = ["o", "a"]
const result = countString(string, lettersToCheck);
//iterate over the array to get the total
var product = 1;
for (int i = 0; i < result.length; i++){
product *= result[i];
}
console.log(product);
Rather than iterating over the strings, however, a different approach is to use regular expressions and .match(). This approach has fewer iterations, although I'm not sure about the low level efficiency, since lots of the comparison is encapsulated by .match():
function countString(str, letters) {
//iterates over the array of letters rather than the string
for (var i = 0; i < letters.length; i++){
count += (str.match(new RegExp(letters[i], "g")) || []).length;
}
return count;
}
const string = "hello my name is " + Ola.toLowerCase()
const lettersToCheck = ["o", "a"]
const result = countString(string, lettersToCheck);
//iterate over the array to get the total
var product = 1;
for (int i = 0; i < result.length; i++){
product *= result[i];
}
console.log(product);
If regex is too much, you could also use .split() to iterate over the characters rather than the string:
function countString(str, letters) {
//iterates over the array of letters rather than the string
for (var i = 0; i < letters.length; i++){
count += str.split(letters[i]).length - 1;
}
return count;
}
const string = "hello my name is " + Ola.toLowerCase()
const lettersToCheck = ["o", "a"]
const result = countString(string, lettersToCheck);
//iterate over the array to get the total
var product = 1;
for (int i = 0; i < result.length; i++){
product *= result[i];
}
console.log(product);
See this post for more information
You can compute the letter frequency each time the phrase changes and then request the product by specifying the letters in the frequency map.
const letterFrequencyMap = (str) =>
str.toLowerCase().split('').reduce((acc, k) =>
acc.set(k, (acc.get(k) ?? 0) + 1), new Map);
const computeProduct = (freq, ...keys) =>
keys.reduce((product, k) => product * (freq.get(k) ?? 1), 1);
// Main
const phrase = "It's about to be noon in a bit.";
const freq = letterFrequencyMap(phrase);
// a = 2; o = 4
console.log(computeProduct(freq, 'a', 'o')); // 8

How can I log the index of each array item?

I'm a beginner and struggling with this exercise. Can anyone tell me why the console is logging the index of both characters as 1. I want it to log the character 'a' every time it appears in the word. So for example, if we ran the function with the word ‘Saturday’ and ‘a’ as below, it should log an array [1,6]. Instead it is logging [1, 1].
const subLength = (word, letter) => {
let wordArray = word.split("");
let indexArray = []
for (i = 0; i < wordArray.length; i++) {
if (wordArray[i] === letter) {
indexArray.push(wordArray.indexOf(letter));
}
}
console.log(indexArray);
}
subLength('Saturday', 'a');
You could take the index i from the loop directly.
String#indexOf returns the first found index, but if you take an index as second parameter it searches from this position.
const subLength = (word, letter) => {
let wordArray = word.split("");
let indexArray = [];
for (let i = 0; i < wordArray.length; i++) { // take let here too
if (wordArray[i] === letter) {
indexArray.push(i);
}
}
console.log(indexArray);
}
subLength('Saturday', 'a');
An approach without using split.
const
subLength = (word, letter) => {
let indexArray = [];
for (let i = 0; i < word.length; i++) {
if (word[i] === letter) indexArray.push(i);
}
console.log(indexArray);
};
subLength('Saturday', 'a');
A simpler method would be to filter over the indexes.
const subLength = (word, letter) => [...Array(word.length).keys()]
.filter(i => word[i] === letter);
console.log(subLength('Saturday', 'a'));

Breaking strings in an array into subarrays

Doing the DNA challenge and so close but clearly misunderstanding prototype.split(""). What's the best way to turn these strings ["AC", "CA", "TA"] into subarrays? [["A","C"]["C","A"]["T","A"]]
function pairElement(str) {
//break into array
var arr = str.split("");
//add new letter (could be refactored as switch)
for (i = 0; i < arr.length; i++) {
if (arr[i] == "G") {
arr[i] += "C";
} else if (arr[i] == "C") {
arr[i] += "G";
} else if (arr[i] == "T") {
arr[i] += "A";
} else if (arr[i] == "A") {
arr[i] += "T";
}
}
//break into arrays again
//this is how I'm trying to use.split to break it up. Doesn't work.
var broken = [];
for (x = 0; x < arr.length; x++) {
broken += arr[x].split("");
}
//return
return arr;
}
console.log(pairElement("GCG"));
you can use .map and split them by ""
var o = ["AC", "CA", "TA"];
var s = o.map(e=> e.split(""));
console.log(s)
You actually have to just push the split result in the broken array and return it !
function pairElement(str) {
//break into array
var arr = str.split("");
//add new letter (could be refactored as switch)
for (i = 0; i < arr.length; i++) {
if (arr[i] == "G") {
arr[i] += "C";
} else if (arr[i] == "C") {
arr[i] += "G";
} else if (arr[i] == "T") {
arr[i] += "A";
} else if (arr[i] == "A") {
arr[i] += "T";
}
}
//break into arrays again
//this is how I'm trying to use.split to break it up. Doesn't work.
var broken = [];
for (x = 0; x < arr.length; x++) {
broken.push(arr[x].split(""));
}
//return
return broken;
}
console.log(pairElement("GCG"));
To answer your 'what's the best way' question, map your arrays into the split versions of themselves:
const subarrays = array.map(pair => pair.split());
Very simple in functional style:
> seq = ['AC', 'CA', 'TA']
[ 'AC', 'CA', 'TA' ]
> seq.map(s => s.split(''))
[ [ 'A', 'C' ], [ 'C', 'A' ], [ 'T', 'A' ] ]
Overall, I'd do some refactoring on the whole function:
var m = new Map([["G", "C"], ["C", "G"], ["A", "T"], ["T", "A"]]);
function pairElement(str) {
return [...str].map(c => [c, m.get(c)]);
}
console.log(pairElement("GCG"));
And if there's a guarantee that the sub-arrays are never mutated, then you can save a good bit of memory by reusing arrays instead of creating them over and over.
var m = new Map([["G", ["G", "C"]], ["C", ["C", "G"]], ["A", ["A", "T"]], ["T", ["T", "A"]]]);
function pairElement(str) {
return [...str].map(c => m.get(c));
}
console.log(pairElement("GCG"));
But to directly answer your question, you can do it without explicit .split() calls. Since you know there's always two characters, you can use parameter destructuring on the strings.
var arr = ["AC", "CA", "TA"];
var s = arr.map(([a, b]) => [a, b]);
console.log(s)
Or even a little shorter using rest syntax, like this:
var arr = ["AC", "CA", "TA"];
var s = arr.map(([...a]) => a);
console.log(s)
Or using spread syntax in an array literal:
var arr = ["AC", "CA", "TA"];
var s = arr.map(s => [...s]);
console.log(s)

Javascript: Determine if all characters in a string are unique and if not, delete duplicate characters

Have an array set up with a[letter][occurences], but struggling with looping through this array, to check for occurences > 1 and removing the ones that are.
function charFreq(s) {
var i, j;
var a = new Array();
for (j = 0; j < s.length; j++) {
for (i = 0; i < a.length; i++) {
if (a[i][0] == s[j]) {
a[i][1]++;
break;
}
}
if (i == a.length) {
a[i] = [s[j], 1];
}
}
return a[i][0];
}
document.write(charFreq("insert string here"));
This is the mess I've come up with so far:
function check(str) {
var c;
for (c=0; c < a.length; c++) {
if(a[c][1] == 1) {
return true;
break;
} else {
return false;
}
}
}
Using ES6 Set:
// :: unique = Array<any>|string => Array<any>
const unique = xs => [...new Set(xs)]
const dedupe = str => unique(str).join('')
console.log(
unique('foo'), // => ['f', 'o']
dedupe('foo'), // => 'fo'
)
Don't do it that way.
function noDups( s ) {
var chars = {}, rv = '';
for (var i = 0; i < s.length; ++i) {
if (!(s[i] in chars)) {
chars[s[i]] = 1;
rv += s[i];
}
}
return rv;
}
alert(noDups("Shoe fly pie, and apple pan dowdy")); // Shoe flypi,andw
As the length of your string gets longer, your code gets slower by a factor roughly equal to the square of the length of the string.
To delete duplicate characters from an string, you can use the next function that made the user #Cerbrus
function find_unique_characters( string ){
var unique='';
for(var i=0; i<string.length; i++){
if(string.lastIndexOf(string[i]) == string.indexOf(string[i])){
unique += string[i];
}
}
return unique;
}
console.log(find_unique_characters('baraban'));
If you only want to return characters that appear occur once in a
string, check if their last occurrence is at the same position as
their first occurrence.
Your code was returning all characters in the string at least once,
instead of only returning characters that occur no more than once
Link to the thread of stackoverflow Remove duplicate characters from string
​
Here's a quick way:
str = str.split('').filter(function(v,i,self){
return self.indexOf(v) == i;
}).join('');
function RemoveDuplicateLetters(input) {
var result = '', i = 0, char = '';
while (i < input.length) {
char = input.substring(i, i+1);
result += char;
input = input.replace(char,'');
}
return result;
}
I can't see a splice version, so here's one:
function uniqueChars(s) {
var s = s.split('');
var c, chars = {}, i = 0;
while ((c = s[i])) {
c in chars? s.splice(i, 1) : chars[c] = ++i;
}
return s.join('');
}
This assumes only alpha characters, and upper case not equal to lower case.
function uniqueChars(string){
var i= 0, L= string.length, ustring= '', next;
while(i<L){
next= string.charAt(i++);
if(ustring.indexOf(next)== -1) ustring+= next;
}
return ustring.replace(/[^a-zA-Z]/g, '');
}
var s1= 'The quick red fox jumps over the lazy brown dog.';
uniqueChars(s1)
/* returned value: (String)
Thequickrdfoxjmpsvtlazybwng
*/
This returns any unique character-
function uniqueArray(array){
return array.filter(function(itm, i, T){
return T.indexOf(itm)== i;
});
}
var s1= 'The quick red fox jumps over the lazy brown dog.';
uniqueArray(s1.split('')).join('');
/* returned value: (String)
The quickrdfoxjmpsvtlazybwng.
*/

Categories

Resources