How to Know if array has same letters as string - javascript

so what I have been trying to acheive is that if I iterate over arr and string and if they have the same letters then some action should be perfomed, for example - if ("both string and array have the same letters"){ "some action" }
const word = "hello";
const arr = ["o", "l", "e", "h"];

const word = "hello";
const arr = ["o", "l", "e", "h"];
const uWord = [...new Set(word)].sort().join()
const uArr = [...new Set(arr)].sort().join()
if (uWord === uArr) {
// do something
}

Here is with Linear time O(n). Check whether both items has same chars and same chars count.
const isMatch = (arr, word, track = {}) => {
arr.forEach((char) => (track[char] = (track[char] ?? 0) + 1));
[...word].forEach((char) => (track[char] = (track[char] ?? 0) - 1));
return !Object.values(track).some((val) => val < 0);
};
console.log(isMatch(["o", "l", "e", "h"], "hello"));
console.log(isMatch(["o", "l", "e", "h", "l"], "hello"));
console.log(isMatch(["o", "o"], "lo"));

Related

How to break lines in javascript using .join

I have 9 strings "a", "b", "c", "d", "e", "f", "g", "h", "i" in a JavaScript array.
const arr = ["a", "b", "c", "d", "e", "f", "g", "h", "i"];
I am printing the value of arr using JavaScript alert box.
but, if I use arr.join(" ") it is expected like:
a b c d e f g h i
but, I want to change the line for every 3rd element.
like:
a b c
d e f
g h i
How can I do this?
You can use a for loop with Array#slice.
const arr = ["a", "b", "c", "d", "e", "f", "g", "h", "i"];
const parts = [];
for(let i = 0; i < arr.length; i += 3){
parts.push(arr.slice(i, i + 3).join(' '));
}
console.log(parts.join('\n'));
This is what I use to chunk arrays:
const chunkSize = 3;
array
.map((_, i) =>
i % itemsPerPage
? undefined
: items.slice(
i,
Math.floor(i / chunkSize) * chunkSize + chunkSize
)
)
.filter(($) => !!$);
So chunk it up and use:
chunkedArray.map((array) => array.join(" ")).join("\n");
The .map used changes all the arrays inside to a b c and then join all of them with a newline character :)
You can also do that with join by using template literal. e.g:
var arr = ["P613221", "W123456", "ew76879", "GDG767"]
var stringWithQuotes = `'${arr.join(`', '`)}'`
console.log({
stringWithQuotes,
query: `SELECT * FROM users WHERE id IN (${stringWithQuotes})`
})
output:
"P613221', 'W123456', 'ew76879', 'GDG767"

JavaScript - Caesar Cipher

I know there have been a few posts about Caesar Ciphers in the past, which I have had a look at, but I haven't found an answer which has helped me to solve this kata, hence my post.
The language is JavaScript. I've written 3 tests, 2 of which are passing so far, but the third is not. I tried to use a nested for loop to loop over the alphabet and the str, and compare them, then shift the alphabet index up/down according to whatever the number was, then push that letter into a new array, and return the joined array at the end.
It's working for positive numbers, but not negatives. (I should also point out that I haven't thought of how to handle spaces yet, I just wanted to get it working for single words first, then take it from there, thanks!)
Any pointers in the right direction would be appreciated.
Kata Instructions:
The function caesarCipher should take a string and a number (n) and return a new string with a Caesar cipher applied. A Caesar cipher replaces each plaintext letter with a different one a fixed number of places up or down the alphabet. N represents the number of shifts up or down the alphabet should be applied. It may be negative or positive.
E.g.
caesarCipher('hello', 2)
--> 'jgnnq'
caesarCipher('hello world!', -3)
--> 'ebiil tloia!'
My tests:
const caesarCipher = require("../katas/caesar-cipher");
const { expect } = require("chai");
describe.only("caesarCipher", () => {
it("returns an empty string when passed an empty string", () => {
const alphabet = [
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z"
];
const str = "";
const num = 2;
const actualResults = caesarCipher(alphabet, str, num);
const expectedResults = "";
expect(actualResults).to.equal(expectedResults);
});
it("returns a string with the letters replaced by the number of shifts up the alphabet", () => {
const alphabet = [
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z"
];
const str = "hi";
const num = 2;
const actualResults = caesarCipher(alphabet, str, num);
const expectedResults = "jk";
expect(actualResults).to.equal(expectedResults);
});
it("returns a string with the letters replaced by the number of shifts down the alphabet", () => {
const alphabet = [
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z"
];
const str = "dog";
const num = -3;
const actualResults = caesarCipher(alphabet, str, num);
const expectedResults = "ald";
expect(actualResults).to.equal(expectedResults);
});
});
My Solution:
function caesarCipher(alphabet, str, num) {
const strToArray = str.split("");
console.log(strToArray);
const cipheredStr = [];
for (let i = 0; i < strToArray.length; i++) {
for (let j = 0; j < alphabet.length; j++) {
if (strToArray[i] === alphabet[j] && Math.sign(num) === 1) {
console.log(Math.sign(num));
cipheredStr.push(alphabet[(j += num)]);
} else if (strToArray[i] === alphabet[j] && Math.sign(num) === -1) {
console.log(Math.sign(num));
console.log(alphabet[(j -= num)]);
cipheredStr.push(alphabet[(j -= num)]);
}
}
}
console.log(cipheredStr.join(""));
return cipheredStr.join("");
}
The Results:
caesarCipher
[]
✓ returns an empty string when passed an empty string
[ 'h', 'i' ]
1
1
jk
✓ returns a string with the letters replaced by the number of shifts up the alphabet
[ 'd', 'o', 'g' ]
-1
g
-1
r
-1
j
jum
1) returns a string with the letters replaced by the number of shifts down the alphabet
2 passing (15ms)
1 failing
1) caesarCipher
returns a string with the letters replaced by the number of shifts down the alphabet:
AssertionError: expected 'jum' to equal 'ald'
+ expected - actual
-jum
+ald
at Context.<anonymous> (spec/caesar-cipher.spec.js:108:30)
at processImmediate (internal/timers.js:456:21)
The problem is that when num is negative, you are doing the mapping:
cipheredStr.push(alphabet[(j -= num)]);
But num is negative. When you subtract a negative number what you are doing is adding its absolute value.
Instead, you should do:
cipheredStr.push(alphabet[j + num]);
Also, note that to compute the index in the alphabet you don't need to put the = in there.
Side notes
I understand that your solution is a work in progress. You have to take into consideration:
What happens when you sum j + num to do the translation and it goes out of boundaries of your alphabet. Same thing could happen with a negative value of num.
In the declaration of the problem, it states that caesarCipher should only accept two parameters, but you are passing the alphabet as first parameter!
Good luck with your code and keep trying :)
let alphabets = 'abcdefghijklmnopqrstuvwxyz';
let arr = alphabets.split('')
// Cipher Get
function getCipher(str= alphabets, shift=3){
return arr.reduce((a, c, i) => {
let result = [...a]
let tIndex = ( i + shift) % arr.length
result[i]=arr[tIndex]
return result;
},[])
}
// Encrypt
let stringToEnc = 'danger'
console.log('Plain Text -', stringToEnc)
let cipheredAlphabets = getCipher()
let encryptedStr = stringToEnc
.toLowerCase()
.split('')
.map(function(p, i){
let indexInAlphabets = arr.findIndex(c => p == c)
return (cipheredAlphabets[indexInAlphabets])
})
let encryptedText = encryptedStr.join('')
console.log('encrypted text - ', encryptedText)
// Decrypt
let cipherForDecrypt = getCipher(alphabets, -3)
let decryptedStr = encryptedText
.toLowerCase()
.split('')
.map(function(p, i){
let indexInAlphabets = cipheredAlphabets.findIndex(c => p == c)
return (arr[indexInAlphabets])
})
console.log('decrypted text - ', decryptedStr.join(''))

How can I add the resulted strings into an array and eliminate duplicates?

I'm new to fairly new to Javascript and I need some help solving the 804. Unique Morse Code Words - Leetcode problem.
I figured how to search return the morse code by using the index of each letter from a word and using it to concatenate the codes at those specific index in the morse code array. The problem is I can't store the results into an Set array excluding the duplicates and returning the length of the Set array.
var letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
var morseCode = [".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."];
var words = ["gin", "zen", "gig", "msg"]
var uniqueMorseRepresentations = function(words) {
for (i = 0; i < words.length; i++) {
let word = words[i];
var result = "";
for (j = 0; j < word.length; j++) {
let letter = word.charAt(j);
let index = letters.indexOf(letter);
result += morseCode[index];
};
console.log(result);
};
};
uniqueMorseRepresentations(words);
The console.log method return the results in 4 separate strings but I don't know how to store them into an array while verifying if there are duplicate.
I'm sorry if the question is sloppy. It's my first one.
Thanks in advance!
Inside your function, create a Set:
const resultSet = new Set();
Then when each result is built up (when you log it), add the resulting morse code to that Set:
resultSet.add(result);
Then you can finally return that Set, or its .size.
I think this should solve your problem. Take an obj, and store the result in that and check if the result is repeating then don't push that result into that array. And the time complexity in this operation would be O(1), so you don't have to worry about it if you want to scale your algorithm.
var letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
var morseCode = [".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."];
var words = ["gin", "zen", "gig", "msg","gig"]
var array = [];
var uniqueMorseRepresentations = function(words) {
let obj = {};
for (i = 0; i < words.length; i++) {
let word = words[i];
var result = "";
for (j = 0; j < word.length; j++) {
let letter = word.charAt(j);
let index = letters.indexOf(letter);
result += morseCode[index];
};
if(!obj[result]){
obj[result] = result;
array.push(result);
}
console.log(result);
};
console.log(array)
};
uniqueMorseRepresentations(words);

Why does map function skip the first element?

I was trying to convert alphabets into ASCII using the following:
var subArr = [["S", "E", "R", "R"], ["C", "V", "M", "M", "N", "!"]];
for (var i in subArr) {
var newStr = subArr[i].map( function(val) {
return val.charCodeAt()
})
}
console.log(newStr)
But it seemed that only the second subarray was converted while the first one was not even considered. Would anyone please help me understand the issue here?
This is the problem with scope of your print statement. Note that you are iterating for each sublist and reassigning the map result to the same variable newStr so when you console.log it at the end it only contains the value corresponding to the last sublist!
var subArr = [["S", "E", "R", "R"], ["C", "V", "M", "M", "N", "!"]];
for (var i in subArr) {
var newStr = subArr[i].map(function(val) {
return val.charCodeAt();
});
console.log(newStr);
}
console.log(newStr) is outside the loop. You need to create a list and push new values to it.
like this:
var subArr = [["S", "E", "R", "R"], ["C", "V", "M", "M", "N", "!"]];
var resultArr = [];
for (var i in subArr) {
resultArr.push(subArr[i].map(function(val) {
return val.charCodeAt();
}));
}
console.log(resultArr);
you re not escaping the first array you just crushing the first array with the second one
var subArr = [
["S", "E", "R", "R"],
["C", "V", "M", "M", "N", "!"]
];
var newStr = [];
for (var i in subArr) {
newStr = newStr.concat(subArr[i].map(function(val) {
return val.charCodeAt()
}))
}
console.log(newStr);
console.log() should be inside(in scope of) for...in loop. In map() function you are converting the array to the character code and assigning it to the variable newStr. So, when the map is executed for the second array element, newStr contains the code of the second element. Thus, printing only for the second array element of subArr.
var subArr = [["S", "E", "R", "R"], ["C", "V", "M", "M", "N", "!"]];
for (var i in subArr) {
var newStr = subArr[i].map( function(val) {
return val.charCodeAt()
});
console.log(newStr)
}
Your log statement is outside the loop, which means it'll print the value of newStr once after the loop has finished executing.
In your loop, you are using the same variable newStr to store value in each iteration. This means the second iteration will overwrite the first one and so on.
If your intention is to have ASCII codes for each character in place of the character itself, you should be doing the following
var arrays = [
["S", "E", "R", "R"],
["C", "V", "M", "M", "N", "!"]
];
let asciiArrays = arrays.map(subArray =>
subArray.map(val => val.charCodeAt())
);
console.log(asciiArrays);

Take all elements from array in a random way?

Hi everyone Can't figure out how can I take element from array in a random way and without repeating. Here is my code:
var letters = [ "A", "A", "B", "B", "C", "C", "D", "D", "E", "E",
"F", "F", "G", "G", "H", "H", "I", "I", "J", "J" ],
cards = document.getElementsByClassName( "cards" ),
cardBoxes = document.getElementsByClassName( "card-boxes" );
//generate random number
function randomNum( nums ) {
return Math.floor( Math.random() * nums.length );
}
//hide letter behind card in random way
function hideLetter() {
for ( var i = cards.length - 1; i >= 0; i-- ) {
var randomLetter = letters[ randomNum(letters) ];
cards[i].textContent = randomLetter;
};
}
hideLetter();
I take element in a random way, but Math.random repeating themselves. I think I have to write some sort of if statment, which will be detect if element was taken two times, but cant figure how to do it. Looking for advice. Thanks.
Here Codepen of problem http://codepen.io/Kuzyo/pen/vdlai
The sure way is to remove element from the array after it was used. This way it will never be repeated
randomise your array, then walk through the randomised array. This has the benefit of the usual "remove elements while using random indices", while keeping the sequence around in case you need a repeat operation that relies on the same random sorting:
function randomize(array) {
var copy = array.slice(),
random = [],
element, pos;
while(copy.length>0) {
pos = (Math.random()*copy.length) | 0; // bit operation forces 32-bit int
subarray = copy.splice(pos, 1);
random.push(subarray[0]);
}
return random;
}
var letters = [ "A", "A", "B", "B", "C", "C", "D", "D", "E", "E",
"F", "F", "G", "G", "H", "H", "I", "I", "J", "J" ],
randomLetters = randomize(letters);
randomLetters.forEach(function(letter) {
// create a card for this letter
});
// do we need it again, in a new random fashion?
// then we can simply call this:
randomLetters = randomize(letters);
Here is my version, with a generator. The function returned by makeRandomGenerator will return random, non-repeating members of inputArray. Once all elements have been used, it will return undefined.
function shuffle(array) {
return array.sort(function() {
return Math.random() > 0.5 ? 1 : -1;
});
}
function makeRandomGenerator(inputArr) {
var arr = inputArr.slice(0);
shuffle(arr);
return function() {
return arr.pop();
}
}
to use:
var letterGenerator = makeRandomGenerator(letters);
function hideLetter() {
for ( var i = cards.length - 1; i >= 0; i-- ) {
var randomLetter = letterGenerator();
if (randomLetter === undefined) {
return;
}
cards[i].textContent = randomLetter;
};
}
hideLetter();
Randomize the array and shift off values from the array :
var letters = [ "A", "A", "B", "B", "C", "C", "D", "D", "E", "E", "F", "F", "G", "G", "H", "H", "I", "I", "J", "J" ],
cards = document.getElementsByClassName( "cards" ),
i = letters.length, j, temp;
while ( --i ) {
j = Math.floor( Math.random() * (i - 1) );
temp = letters[i];
letters[i] = letters[j];
letters[j] = temp;
}
for ( var i = cards.length; i--; ) {
cards[i].innerHTML = letters.shift();
}
FIDDLE

Categories