Get number of words in an array starting with certain characters - javascript

I'm trying to solve a problem on a testing website and I'm getting confused on trying to find a way to match the letters of a passed in array wordlist.
In the below example it should be returning 2, as ye should be matched twice - in yesterday and yellow.
Without using a RegEx what would be the best way be to go about getting a passed in wordlist to return a number amount based on the 2nd argument input?
This is the code I have so far, that isn't working:
let wordList = ['yesterday', 'develop', 'environment', 'yellow', 'yikes', 'envious']
const countingLetters = (words, inputStart) => {
let total = 0;
for (let i = 0; i < words.length; i++) {
if (inputStart == words[i]) {
total += 1;
}
}
return total;
};
console.log(countingLetters(wordList, 'ye'));

To do what you require without a regex, you can use the filter() function, to search the array by a given condition, and the indexOf() method to ensure that the match is at the start of the string:
let wordList = ['yesterday', 'develop', 'environment', 'yellow', 'yikes', 'envious']
const countingLetters = (words, inputStart) =>
words.filter(word => word.indexOf(inputStart) === 0).length;
console.log(countingLetters(wordList, 'ye'));

Related

Algorithm to calculate maximum possible length of a String

Problem:
Given an array of strings arr. String s is a concatenation of a sub-sequence of arr which have unique characters.
Return the maximum possible length of s
Examples:
Input: arr = ["un","iq","ue"]
Output: 4
Explanation: All possible concatenations are "","un","iq","ue","uniq" and "ique".
Maximum length is 4.
Input: arr = ["cha","r","act","ers"]
Output: 6
Explanation: Possible solutions are "chaers" and "acters".
My solution:
var maxLength = function(arr) {
if(!arr || arr.length === 0) return 0;
let word = "";
arr.sort((a,b) => b.length - a.length);
let set = new Set();
const removeFromSet = (str) => {
for(let i=0; i<str.length; i++) {
set.delete(str[i]);
}
}
const isInSet = (str) => {
for(let i=0; i<str.length; i++) {
if(set.has(str[i])) {
removeFromSet(str.substring(0, i));
return true;
}
else
set.add(str[i]);
}
return false
}
for(let i=0; i<arr.length; i++) {
if(!isInSet(arr[i])) {
word += arr[i];
}
}
return word.length;
};
It fails for the input: ["ab","cd","cde","cdef","efg","fgh","abxyz"]
It should return 11, but my solution returns 9.
I know that my solution is calculating: "abxyzcdef" and it should be: "abxyzfghcde". Does anyone know what I am doing wrong?
Thanks
Hole algorithm is recursivly, starting with only the string-array. If the second parameter str is not defined than it's setted to an empty strin (only at start).
Iterate through the string-array look if there is a builded string. If so than split the new teststring in chars and look if there exists at least one char (with Array#some) that is included in the builded string. If this condition is as well true than the string would not be contain unique chars so we can continue. Otherwise this is till now a possible sollution.
Now take the array and remove all the teststrings which have been tried (included the actual tested) because testing with them isn't usefull. Call the algorithm itself recursivly with shortened string-array and the string extended with the actual teststring.
Look if the length of the acual teststring plus the return value of recursiv call is greater than maximum than actualisize it.
After iterateing through all testrings from the array return the maximum length from an allowed string.
Extended: I check at start all strings with Array.filter for words with multiple same chars so e.g. 'abba' will not be tested.
function maxLength(array, str) {
if (str === undefined) {
str = '';
array = array.filter(elem => elem.split('').every((char, key) => !(elem.slice(key+1)).includes(char)));
};
array = array.filter(elem => elem.split('').every((char, key) => !(elem.slice(key+1)).includes(char)));
let max=0;
for (let i=0; i<array.length; i++) {
let test= array[i];
if (str.length && test.split('').some(char => str.includes(char))) {
continue;
} else {
let len = test.length + maxLength(array.slice(i), str + test);
if (len>max) max=len;
}
}
return max;
}
console.log( maxLength(["un","iq","ue"]) );
console.log( maxLength(["cha","r","act","ers"]) );
console.log( maxLength(["ab","cd","cde","cdef","efg","fgh","abxyz"]) );
console.log( maxLength(["yy","bkhwmpbiisbldzknpm"]) );
I found your logical fault: You only look straight forward and if one string not match you leave this one out and testing the next and go on like this.
But if one string matches you never look if possible another would be better.
Explanation:
I will explain it a little more. These are your sorted strings for testing:
["abxyz", "cdef", "cde", "efg", "fgh", "ab", "cd"]
You tried these combinations(first the tested good string and second your actual candidate) and afterwardes result for testing:
abxyz => ok
abxyz cdef => ok
abxyz cdef cde => false
abxyz cdef efg => false
abxyz cdef fgh => false
abxyz cdef ab => false
abxyz cdef cd => false
So your max-length is 9 (choose the first and the second string). But the solution abxyz cde fgh you don't take a look on it. For this you had to look instead of cdef for the shorter cde which is in combination with fgh the solution.
This is only the explanation why this don't work but not how you can solve it ;).

Return count of duplicates

Here is the prompt: Write a function that will return the count of distinct case-insensitive alphabetic characters and numeric digits that occur more than once in the input string. The input string can be assumed to contain only alphabets (both uppercase and lowercase) and numeric digits.
Get all non-unique values (i.e.: duplicate/more than one occurrence) in an array
Get all unique values in a JavaScript array (remove duplicates)
I used variances of the above questions/answers and tried to amend it for what I am looking for- the count of how many elements are found more than once
var arr = 'Indivisibilities';
var sorted_arr = arr.toLowerCase().split('').sort();
let count = 0;
let duplicateCount = (parm1) => {
for (var i = 0; i < sorted_arr.length - 1; i++) {
if (sorted_arr[i + 1] == sorted_arr[i]) {
count ++;
}
} return count;
}
duplicateCount(arr);
Count returns 7, what is expected is 2. Also, I would really like to avoid using a for loop. I'm hoping this can be done with .forEach or something method. ** I'm still pretty knew to code so please try not to do any one liners :) I appreciate the efficiency, but I'm still trying to understand the logic
You can use reduce and filter
Change string to lowercase
Split string by ''
Use each element as key, if it is already present increase it's count by 1 else set it to 1
Filter values which are greater than 1 to see duplicates
Get length of filtered array
var str = 'Indivisibilities';
let duplicateCount = (str) => {
let dups = str.toLowerCase().split('').reduce((op,inp)=>{
op[inp] = op[inp] || 0
op[inp]++
return op
},{})
return Object.values(dups).filter(v=>v>1).length
}
console.log(duplicateCount(str));

JavaScript: Sentence variations using the reduce function

For search purposes, given a string like BBC Sport I want to construct an array that looks like:
[ 'BBC', 'BB', 'B', 'Sport', 'Spor', 'Spo', 'Sp', 'S' ]
I've implenented it using 2 for loops:
const s = "BBC sport";
const tags = [];
const words = s.split(" ");
for (let word of words) {
const wl = word.length;
for (let i = 0; i < wl; i++) {
tags.push(word.substr(0, wl - i));
}
}
// tags now equals [ 'BBC', 'BB', 'B', 'Sport', 'Spor', 'Spo', 'Sp', 'S' ]
However, I'd like to implement it, if possible, with the reduce function instead of for loops.
How would you solve it?
Honestly I'd write the code the way you did. Two loops are readable, maintainable and fast.
If you really need a oneliner:
s.split(" ").flatMap(word => Array.from(word, (_, i) => word.slice(0, i + 1)))
Here is a solution relying on function generators (which I would use) and a solution with reduce (as you asked) (which I wouldn't personally use), accepting an input string and a separator.
In your case, the separator is blankspace, of course, but it can be customized.
The below code will iterate through the input string and slice the relevant part of the string for each occurrence, by capitalizing it (since it looks like you are).
This should be elastic enough and, at the same time, easy to customize by eventually adding additional parameters to the toTagList method, or allowing further transformations since it's iterable.
const s = "BBC sport";
function* toTagList(input, separator) {
// split by the separator.
for (const block of input.split(separator)) {
// For each string block, split the whole word.
var splitted = block.split('');
// slice the input array by taking from the first character to the last one, then decrease to get only the previous portions of said word.
for (var i = splitted.length; i > 0; i--) {
// Finally, yield the capitalized string.
yield capitalize(splitted.slice(0, i).join(''));
}
}
}
// this just capitalizes the string.
function capitalize(input) {
return input.charAt(0).toUpperCase() + input.substring(1, input.length);
}
console.log([...toTagList(s, ' ')]);
If you really want to do that with reduce:
const s = "BBC sport";
const tags = s.split(' ').reduce((acc, next) => {
return acc.push(...Array.from({length: next.length}).map((_, i) => {
return (next.split('').slice(0, i + 1)).join('')
})), acc;
}, [])
console.log(tags);

Format casing of names when first letter is repeated

I have a function which takes an array of names and returns a new array with each name's first letter transformed to uppercase (and the remaining letters lowercase).
function capMe(arr) {
let newArr = [];
arr.forEach(function(name) {
name = name.replace(name[0], name[0].toUpperCase());
for(let i = 1; i < name.length; i++) {
name = name.replace(name[i], name[i].toLowerCase());
}
newArr.push(name);
});
return newArr;
}
This works for the vast majority of the time. For example, if I call the function like this:
console.log(capMe(['jACKSON', 'pAM', 'wiLliAm']));
I will receive the desired output of > Array ["Jackson", "Pam", "William"].
However, there is one case in which this function does not work. If I call the function with a name which has the first letter repeated, every letter will be lowercase except for the second occurrence of the letter.
For example, If I add gEORGANN to the previous example, I will receive this output:
> Array ["georGann", "Jackson", "Pam", "William"]
How do I solve this issue?
Your current logic is not doing what you think it is. Consider the following line which appears in the loop over each name:
name = name.replace(name[i], name[i].toLowerCase());
This is replacing the first character only which is equal to name[i] with the lowercase version of that letter. Here is how this is throwing off your logic with the input gEORGANN. First, you uppercase the first g, to get GEORGANN. Then, when the loop hits the fourth position, which is a capital G, it replaces the first G with a lowercase g. This leaves us with gEORGANN, but it is not what you intend. The reason for this is that replace just hits the first occurrence.
You might be able to remedy this by doing a replace all instead of a replace. But why not just take the first character in uppercase concatenated with the remainder of the string in lowercase:
arr = ['georGann', 'jACKSON', 'pAM', 'wiLliAm'];
newArr = [];
arr.forEach(function(name) {
newName = name.charAt(0).toUpperCase() + name.substring(1).toLowerCase()
newArr.push(newName);
});
console.log(arr);
console.log(newArr);
Here you go:
const capMe = (arr = []) => {
return arr.map((name) => {
const [first, ...rest] = name;
return `${first.toUpperCase()}${rest.join('').toLowerCase()}`;
});
}
console.log(capMe(['foo', 'foZBaz']));
Your coding logic is fine. The problem is the order of operations. Please see below;
function capMe(arr) {
let newArr = [];
arr.forEach(function(name) {
name = name.toLowerCase();
name = name.replace(name[0], name[0].toUpperCase());
newArr.push(name);
});
return newArr;
}
console.log(capMe(['gEORGANN', 'pAM', 'wiLliAm', 'AA']));

How to get the length of every word in a string [duplicate]

This question already has answers here:
How to get the length of words in a sentence?
(4 answers)
Closed 3 years ago.
I'm new to coding and have been given this question to solve.
The question I have been given is this;
Create a function that takes a string and returns an array of the lengths of each word in the string.
E.g. 'pineapple and black bean curry' => [9, 3, 5, 4, 5]
The code that I have written is this;
function getWordLengths(str) {
let len = []
let words = str.split()
for (let i = 0; i < words.length; i++){
len.push(words[i])}
return len
}
My code will be run against this test;
describe("getWordLengths", () => {
it("returns [] when passed an empty string", () => {
expect(getWordLengths("")).to.eql([]);
});
it("returns an array containing the length of a single word", () => {
expect(getWordLengths("woooo")).to.eql([5]);
});
it("returns the lengths when passed multiple words", () => {
expect(getWordLengths("hello world")).to.eql([5, 5]);
});
it("returns lengths for longer sentences", () => {
expect(getWordLengths("like a bridge over troubled water")).to.eql([
4,
1,
6,
4,
8,
5
]);
});
});
Dose anyone have any suggestion of haw to make my code work?
You can use string#split and then use map to get the length of each word.
let string = 'pineapple and black bean curry',
result = string.split(/\s+/).map(({length}) => length);
console.log(result)
I changed .split() to .split(' ') and len.push(words[i]) to len.push(words[i].length).
const text = 'pineapple and black bean curry'; //[9, 3, 5, 4, 5]
function getWordLengths(str) {
let len = [];
let words = str.split(' ');
for (let i = 0; i < words.length; i++){
len.push(words[i].length);
}
return len;
}
console.log(getWordLengths(text));
You are not passing any separator to your split function.
So, split the string at every " ", then calculate the length of each word from the resulting array using map:
let string = 'pineapple and black bean curry';
console.log(string.split(' ').map(a => a.length))
\b in a regex expression to split words.
let line='pineapple and black bean curry';
let results=line.match(/\b[^\s]+?\b/g).map(r=>r.length);
console.log(results)
There are quite a few ways to do this buddy.
The simplest way would probably be to do as you attempted, i.e., to use the .split() feature. It works only when used rightly. You have forgotten to split the string based on a separator. And here since you are interested in individual words, the separator should be a space. ' '. just map the lengths of the words onto a new array and print it out.
let string = 'pineapple and black bean curry';
let words = string.split(' ');
console.log(words.map(word => word.length))
If you don't want to use map or split functionalities and want to do it using straightforward manual ways, you can do the following: In this , you just keep a counter variable which you increment as long as you don't encounter a space or end of the string and then reset it at the start of the next word.
let string = 'pineapple and black bean curry';
let count = 0, count_array = [];
let x = string.length;
for(i=0;i<=x;i++){
if(string[i]==' ' || string[i]=='\0' || i==x){
count_array.push(count);
count=0;
}
else{
count++;
}
}
console.log(count_array);

Categories

Resources