Take all elements from array in a random way? - javascript

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

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(''))

Append ordinal suffixes ('-st', '-nd', '-rd', '-th') based on the item index

Say, I have an array of option values, like:
var arr = ["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"];
And I need to translate that into array of formatted strings, like:
var result = ['1-st option is "a"', '2-nd option is "b", '3-rd option is "c"', '4-th option is "d"',...];
I managed to achieve most part of it with:
var result = [];
for(var i = 0; i < arr.length; i++){
result.push((i+1)+' option is "'+arr[i]+'"');
}
It produces the strings, like 1 option is "a", so on.
But I can't seem to cope with those suffixes ('-st', '-nd', '-rd', '-th'). Would you, guys, help me out with the issue? Thanks!
You may put necessary suffixes into array and pick the one that corresponds to your index:
const arr = [...'abcdefghijklmnopqrstuvwxyz'];
const suffixes = ['th', 'st', 'nd', 'rd'];
const result = arr.map((item, i) =>
(idx = ~~(i % 10) + 1 > 3 || ~~(i / 10) == 1 ? 0 : ~~(i % 10) + 1,
`${i+1}-${suffixes[idx]} options is '${item}'`));
console.log(result);
.as-console-wrapper {min-width: 100%}
Try this Code it works :
https://en.wikipedia.org/wiki/Ordinal_indicator#English
-st is used with numbers ending in 1 (e.g. 1st, pronounced first)
-nd is used with numbers ending in 2 (e.g. 92nd, pronounced ninety-second)
-rd is used with numbers ending in 3 (e.g. 33rd, pronounced thirty-third)
As an exception to the above rules, all the "teen" numbers ending with 11, 12 or 13 use -th (e.g. 11th, pronounced eleventh, 112th, pronounced one hundred [and] twelfth)
-th is used for all other numbers (e.g. 9th, pronounced ninth).
var arr = ["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"];
function addSuffix(i) {
var j = i % 10,
k = i % 100;
if (j == 1 && k != 11) {
return i + "-st";
}
if (j == 2 && k != 12) {
return i + "-nd";
}
if (j == 3 && k != 13) {
return i + "-rd";
}
return i + "-th";
}
var result = [];
for (var i = 0; i < arr.length; i++) {
result.push(`${addSuffix(i + 1)} option is '${arr[i]}'`);
}
console.log(result);
You can create a function with modulo % that handles that for you, for instance:
function calc_suffix(number) {
let rest = number % 10;
if(rest === 1 && number != 11) { return 'st'; }
else if(rest === 2 && number != 12) { return 'nd'; }
else if(rest === 3 && number != 13) { return 'rd'; }
else { return 'th'; }
}
The end result would look like:
var result = [];
for(var i = 0; i < arr.length; i++){
result.push((i+1) + "-" + calc_suffix(i+1) + " option is "'+arr[i]+'"');
}
try this:
const arr= ["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 ordinal_suffix_of = (n) => (["st","nd","rd"][((n+90)%100-10)%10-1] || "th")
const result = arr.map((res,i)=> `${i+1}-${ordinal_suffix_of(i+1)} option is '${res}'`);
console.log(result);

Javascript: How do I check if an array contains exactly another array?

Suppose I have arrays parent and child. I want to check if a child exists inside a parent array. The ordering matters.
Example:
parent = ["x", "a", "b", "c", "d", "e", "f", "g"]
child = ["a", "b", "c"]
//returns true
Example:
When parent has a different order:
parent = ["x", "g", "b", "c", "d", "e", "f", "a"]
child = ["a", "b", "c"]
//It should return false
How would I achieve this in Javascript?
Edit: I have tried this How to check if an array contains another array? but it did not work for my case
You can run a loop for child and change the index accordingly. You can also use a match variable to detect change in the sequence.
RETURN TRUE
var parent = ["x", "a", "b", "c", "d", "e", "f", "g"]
var child = ["a", "b", "c"];
var initIndex = parent.indexOf(child[0]);
var match = true;
for(var i=1; i<child.length; i++){
var varIndex = parent.indexOf(child[i]);
if( varIndex === initIndex+1){
initIndex = varIndex;
continue;
}
match = false;
}
console.log(match);
RETURN FALSE
var parent = ["x", "g", "b", "c", "d", "e", "f", "a"]
var child = ["a", "b", "c"];
var initIndex = parent.indexOf(child[0]);
var match = true;
for(var i=1; i<child.length; i++){
var varIndex = parent.indexOf(child[i]);
if( varIndex === initIndex+1){
initIndex = varIndex;
continue;
}
match = false;
}
//return false
console.log(match);
USING STRING OPERATION
You can also convert the array to string to avoid those loop:
var parent = ["x", "g", "b", "c", "d", "e", "f", "a"]
var child = ["a", "b", "c"]
var parentStr = parent.toString();
var match = parentStr.indexOf(child.toString()) !== -1;
//return false
console.log(match);
parent = ["x", "a", "b", "c", "d", "e", "f", "g"]
child = ["a", "b", "c"]
parentStr = parent.toString();
match = parentStr.indexOf(child.toString()) !== -1;
//return true
console.log(match);
Convert the array to string by using JSON.stringify() and remove the square brackets from child string.
Now check the indexOf child in parent to check if it contains the child.
let parent = ["x", "a", "b", "c", "d", "e", "f", "g"];
let child = ["a", "b", "c"];
var parStr = JSON.stringify(parent);
var chldStr = JSON.stringify(child).replace('[', '').replace(']', '')
console.log(parStr.indexOf(chldStr) !== -1);
I wrote a function for this a while back that takes some paramenters:
Array.prototype.containsArray = function (child, orderSensitivity, caseSensitivity, typeSensitivity) {
var self = this;
if (orderSensitivity) return orderSensitiveComparer();
else return orderInsensitiveComparer();
function orderSensitiveComparer() {
var resultArry = [],
placeholder = 0;
if (child.length > self.length) return false;
for (var i = 0; i < child.length; i++) {
for (var k = placeholder; k < self.length; k++) {
if (equalityComparer(self[k], child[i])) {
resultArry.push(true);
if (resultArry.length === child.length) return true;
placeholder = k + 1;
break;
}
else resultArry = [];
}
}
return false;
}
function orderInsensitiveComparer() {
for (var i = 0; i < child.length; i++) {
var childHasParentElement = false;
for (var k = 0; k < self.length; k++) {
if (equalityComparer(child[i], self[k])) {
childHasParentElement = true;
break;
}
}
if (!childHasParentElement) return false;
}
return true;
}
function equalityComparer(a, b) {
if (caseSensitivity && typeSensitivity) return caseSensitiveEq(a, b) && typeSensitiveEq(a, b);
else if (!caseSensitivity && typeSensitivity) return caseInsensitiveEq(a, b) && typeSensitiveEq(a, b);
else if (caseSensitivity && !typeSensitivity) return caseSensitiveEq(a, b) && typeInsensitiveEq(a, b);
else if (!caseSensitivity && !typeSensitivity) return caseInsensitiveEq(a, b) && typeInsensitiveEq(a, b);
else throw "Unknown set of parameters";
function caseSensitiveEq(a, b) {
return a == b;
}
function caseInsensitiveEq(a, b) {
return (a + "").toLowerCase() == (b + "").toLowerCase();
}
function typeSensitiveEq(a, b) {
return typeof(a) === typeof(b);
}
function typeInsensitiveEq(a, b) {
return true;
}
}
}
var parent = [1, 2, 3, "a", "b", "c"];
var child = [1, 2, 3];
var child2 = ["1", "2", "3"];
var child3 = ["A", "b", "C"];
var child4 = ["a", "b", "c"];
var child5 = ["c", "b", "a"];
// Tests:
console.log(parent.containsArray(parent));
console.log(parent.containsArray(child));
console.log(parent.containsArray(child2));
// parent to child 2, order sensitive, not case, not type. => true.
console.log(parent.containsArray(child2, true, false, false));
// parent to child 2, order, not case, type. => false. b/c of type.
console.log(parent.containsArray(child2, true, false, true));
// parent to child 3, order, not case, type. => true.
console.log(parent.containsArray(child3, true, false, true));
// parent to child 4, order, case and type => true.
console.log(parent.containsArray(child4, true, true, true));
// parent to child 4, not order, case and type. => true.
console.log(parent.containsArray(child4, false, true, true));
// parent to child 5, not order case or type => true.
console.log(parent.containsArray(child5));
I have a simple method for small sized arrays of this problem.
First join the array to a string, see Array/join
Search substring, see String/indexOf
parent = ["x", "a", "b", "c", "d", "e", "f", "g"];
child = ["a", "b", "c"];
function matchSubArray(parent, child) {
parentStr = parent.join('');
childStr = child.join('');
return parentStr.indexOf(childStr) != -1;
}
matchSubArray(parent, child);
var parent = ["x", "g", "b", "c", "d", "e", "f", "a"]
var child = ["a", "b", "c"]
if(parent.join("").search(child.join("")) === -1) {
console.log("Not found");
} else {
console.log("found")
}

How to remove all the odd indexes (eg: a[1],a[3]..) value from the array

I have an array like var aa = ["a","b","c","d","e","f","g","h","i","j","k","l"]; I wanted to remove element which is place on even index. so ouput will be line aa = ["a","c","e","g","i","k"];
I tried in this way
for (var i = 0; aa.length; i = i++) {
if(i%2 == 0){
aa.splice(i,0);
}
};
But it is not working.
Use Array#filter method
var aa = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"];
var res = aa.filter(function(v, i) {
// check the index is odd
return i % 2 == 0;
});
console.log(res);
If you want to update existing array then do it like.
var aa = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"],
// variable for storing delete count
dCount = 0,
// store array length
len = aa.length;
for (var i = 0; i < len; i++) {
// check index is odd
if (i % 2 == 1) {
// remove element based on actual array position
// with use of delete count
aa.splice(i - dCount, 1);
// increment delete count
// you combine the 2 lines as `aa.splice(i - dCount++, 1);`
dCount++;
}
}
console.log(aa);
Another way to iterate for loop in reverse order( from last element to first ).
var aa = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"];
// iterate from last element to first
for (var i = aa.length - 1; i >= 0; i--) {
// remove element if index is odd
if (i % 2 == 1)
aa.splice(i, 1);
}
console.log(aa);
you can remove all the alternate indexes by doing this
var aa = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"];
for (var i = 0; i < aa.length; i++) {
aa.splice(i + 1, 1);
}
console.log(aa);
or if you want to store in a different array you can do like this.
var aa = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"];
var x = [];
for (var i = 0; i < aa.length; i = i + 2) {
x.push(aa[i]);
}
console.log(x);
You can use .filter()
aa = aa.filter((value, index) => !(index%2));
You can use temporary variable like below.
var a = [1,2,3,4,5,6,7,8,9,334,234,234,234,6545,7,567,8]
var temp = [];
for(var i = 0; i<a.length; i++)
if(i % 2 == 1)
temp.push(a[i]);
a = temp;
in Ecmascript 6,
var aa = ["a","b","c","d","e","f","g","h","i","j","k","l"];
var bb = aa.filter((item,index,arr)=>(arr.splice(index,1)));
console.log(bb);
const aa = ["a","b","c","d","e","f","g","h","i","j","k","l"];
let bb = aa.filter((items, idx) => idx % 2 !== 0)
I read here that splice has O(N) time complexity. Don't use it in a loop!
A simple alternative for removing odd indexes in place:
for (let idx = 0; idx < aa.length; idx += 2)
aa[idx >> 1] = aa[idx];
aa.length = (aa.length + 1) >> 1;
I use x >> 1 as a shortcut to Math.floor(x/2).

Categories