Given a sorted array, I'd like to create a new, 2D array containing arrays of matching elements. Similar to the behavior of python's itertools.groupby
Example:
input = ['a','a','a','a','d','e','e','f','h','h','h','i','l','m','n','r','s','s','t','u','v','y','y']
output = [ ['a','a','a','a'], ['d'], ['e','e'], ['f'], ['h','h','h'], ['i'], ['l'], ['m'], ['n'], ['r'], ['s','s'], ['t'], ['u'], ['v'], ['y','y']]
You could check the predecessor and add a new array before pushing to last item.
var input = ['a', 'a', 'a', 'a', 'd', 'e', 'e', 'f', 'h', 'h', 'h', 'i', 'l', 'm', 'n', 'r', 's', 's', 't', 'u', 'v', 'y', 'y'],
output = input.reduce(function (r, a, i, aa) {
if (aa[i - 1] !== a) {
r.push([]);
}
r[r.length - 1].push(a);
return r;
}, []);
console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }
For non sorted items, you could use a closure over a hash table.
var input = ['a', 'a', 'a', 'a', 'y', 'h', 'h', 'i', 'l', 'e', 'e', 'f', 'h', 'm', 'n', 'r', 's', 'y', 'd', 's', 't', 'u', 'v'],
output = input.reduce(function (hash) {
return function (r, a) {
if (!hash[a]) {
hash[a] = [];
r.push(hash[a]);
}
hash[a].push(a);
return r;
};
}(Object.create(null)), []);
console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use Array.prototype.join() with parameter "", String.prototype.match() with RegExp /([a-z]+)(?=\1)\1|[^\1]/g to match one or more "a" through "z" followed by captured characters, or not captured group, .map(), .split()
var input = ['a', 'a', 'a', 'a'
, 'd', 'e', 'e', 'f'
, 'h', 'h', 'h', 'i'
, 'l', 'm', 'n', 'r'
, 's', 's', 't', 'u'
, 'v', 'y', 'y'];
var res = input.join("").match(/([a-z]+)(?=\1)\1|[^\1]/g).map(c => c.split(""));
console.log(res);
Note: This will work even if the array is not sorted:
var input = ['a','b','c','d','a','d','e','e','f','h','h','h','i','l','m','n','r','s','s','t','u','v','y','y'];
function group(arr) {
var hash = {};
return arr.reduce(function(res, e) {
if(hash[e] === undefined) // if we haven't hashed the index for this value
hash[e] = res.push([e]) - 1; // then hash the index which is the index of the newly created array that is initialized with e
else // if we have hashed it
res[hash[e]].push(e); // then push e to the array at that hashed index
return res;
}, []);
}
console.log(group(input));
Related
/*
pattern:
e,b,c,d,i,f,g,h,o,j,k,l,m,n,u,p,q,r,s,t,a,v,w,x,y,z
I want to sort my words from arr by 2nd letter of each word according to my given pattern.
['aobcdh','aiabch','obijkl']
#output should be:
obijkl
aiabch
aobcdh
*/
// I tried this way:
let pattern = ['e', 'b', 'c', 'd', 'i', 'f', 'g', 'h', 'o', 'j', 'k', 'l', 'm', 'n', 'u', 'p', 'q', 'r', 's', 't', 'a', 'v', 'w', 'x', 'y', 'z']
let arr = ['aiabch', 'aobcdh', 'obijkl', 'apcsdef', 'leeeeeeeeeeeeeeee']
let refArr = []
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < pattern.length; j++) {
if (pattern[j] === arr[i][1]) {
refArr.push(j)
}
}
}
console.log(refArr)
// now what next?
You can use the sort method and the indexOf function
let pattern = ['e', 'b', 'c', 'd', 'i', 'f', 'g', 'h', 'o', 'j', 'k', 'l', 'm', 'n', 'u', 'p', 'q', 'r', 's', 't', 'a', 'v', 'w', 'x', 'y', 'z']
let arr = ['aiabch', 'aobcdh', 'obijkl', 'apcsdef', 'leeeeeeeeeeeeeeee']
const newArr = arr.sort((a, b) => pattern.indexOf(a[1]) - pattern.indexOf(b[1]))
console.log(newArr)
You could generate an object with the order values and sort by this values.
If necessary convert the key to lower case and/or take a default value for sorting unknown letters to front or end.
const
pattern = 'ebcdifghojklmnupqrstavwxyz',
array = ['aobcdh', 'aiabch', 'obijkl'],
order = Object.fromEntries(Array.from(pattern, (l, i) => [l, i + 1]));
array.sort((a, b) => order[a[1]] - order[b[1]]);
console.log(array);
Also, you can try this if you does not know Array methods.
let pattern = ['e', 'b', 'c', 'd', 'i', 'f', 'g', 'h', 'o', 'j', 'k', 'l', 'm', 'n', 'u', 'p', 'q', 'r', 's', 't', 'a', 'v', 'w', 'x', 'y', 'z'], arr = ['aiabch', 'aobcdh', 'obijkl', 'apcsdef', 'leeeeeeeeeeeeeeee'], refArr = []
arr.forEach(a => pattern.includes(a[2]) ? refArr.push(a) : null)
console.log(refArr)
You must reverse your cross loops:
for(let i = 0; i < pattern.length; ++i) {
for(let j = 0; j < arr.length; ++j) {
if(pattern[i] === arr[j][1]) refArr.push(arr[j]);
}
}
Javascript beginner here. This function is supposed to show the position of any given letter in the English alphabet. It seems to run fine, but along with the result, I get an undefined error. Where is this coming from?
var 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'];
function position(letter){
letter = letter.toLowerCase();
for (var i = 0; i < alphabet.length; i++) {
if (alphabet[i] === letter){
console.log('Position in the alphabet is: ' + i);
break;
}
}
};
console.log(position("Z"));
Change:
console.log(position("Z"));
to:
position("Z");
Function position does not return anything--that is why you are getting undefined.
You aren't return any values from position(...) function. To fix the undefined error, you might want to return null if no result is found, like the example:
var 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'];
function position(letter){
letter = letter.toLowerCase();
for (var i = 0; i < alphabet.length; i++) {
if (alphabet[i] === letter){
return 'Position in the alphabet is: ' + i;
}
}
return null;
};
console.log(position("Z"));
The undefined you are seeing in the console is not an error at all. Instead, it is the result of the console.log() statement in last line of code, as #Russ mentioned. It is logging what it received after executing position("Z") - which is actually nothing or undefined.
If you wish to be able to use console.log() for the output of your function, you could have it return a string. This would also eliminate the need for a break; statement in your for loop. You might include a "not found" type of default statement as well to protect against an actual error. (#Dorado's null default is a good alternative.) Here's what my suggestion might look like for your code:
var 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'];
function position(letter){
letter = letter.toLowerCase();
for (var i = 0; i < alphabet.length; i++) {
if (alphabet[i] === letter){
return('Position in the alphabet is: ' + i);
}
}
return 'Character not found in the alphabet!';
};
console.log(position("Z"));
This would give you the single console output you desire, remove the undefined from your console, and allow you to use this function in other code.
your function could be simply this:
var 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'];
function position=(letter)=> {
console.log(`Position in the alphabet is: ${alphabet.findIndex(el=>el===letter.toLowerCase())}`)
}
position("Z");
If I have the code below to generate random characters, how can I code it to generate those same characters excluding some values? I.e. corresponding to var charactExclude.
Ex:
function makeid(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
var charactExclude = document.getelementbyID(character).content.text
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result
}
console.log(makeid(10))
Here's how I would go about this:
First select your element containing the excluded characters (You have some errors in your JS) You can split this into an array using .split('') and use the [...new Set(Your array here)] pattern to remove duplicates at this point.
Then create a new variable for the filtered string, and loop through replacing the characters you do not want to include.
Finally, use this new variable in the creation of your string.
function makeid(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactExclude = [
// Using a Set efficiently removes duplicates, and will speed up the loop below, and the ... expands them back into an array
...new Set(
// Using split('') will turn the string into an array of characters
document.getElementById("character").innerText.split('')
)
];
// Create a new variable, and then loop through the charactExclude array, removing undesired chars
var charactersFiltered = characters
for (var i = 0; i < charactExclude.length; i++) {
charactersFiltered = charactersFiltered.replace(charactExclude[i], '')
}
for (var i = 0; i < length; i++) {
result += charactersFiltered.charAt(Math.floor(Math.random() * charactersFiltered.length));
}
return result
}
console.log(makeid(100))
<div id="character">ABCDEFG</div>
I admit this might be a little tortuous as solution...
/*
* Char codes ranges:
* 0-9 -> 48-57
* A-Z -> 65-90
* a-z -> 97-122
*/
function makeId(idLength, charsToExclude = []) {
// list of all invalid char codes between '0' (char code 48) and 'z' (char code 122)
const invalidCharCodes = [58, 59, 60, 61, 62, 63, 64, 91, 92, 93, 94, 95, 96];
// add to the invalid char list any char passed as parameter
if (charsToExclude.length > 0) {
charsToExclude.forEach(char => invalidCharCodes.push(char.charCodeAt(0)))
}
let id = '';
while (id.length < idLength) {
let charCode;
do {
charCode = Math.floor(Math.random() * (122 - 48 + 1)) + 48;
} while (invalidCharCodes.indexOf(charCode) >= 0)
id += String.fromCharCode(charCode);
}
return id;
}
// test
console.log('should return an ID containing digits and letters (either lower or upper case):', makeId(10));
console.log('should return an ID containing only digits:', makeId(10, ['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', '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']));
console.log('should return an ID containing only letters (either lower or upper case):', makeId(10, ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']));
console.log('should return an ID containing only lower case letters:', makeId(10, ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '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']));
console.log('should return an ID containing only upper case letters:', makeId(10, ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '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']));
console.log('should return an ID containing only 0s:', makeId(10, ['1', '2', '3', '4', '5', '6', '7', '8', '9', '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', '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']));
You could use Array.filter for that
const alphabetAndNumbers = () => [...Array(26)]
.map((x, i) => String.fromCharCode(i + 65))
.concat([...Array(26)].map((x, i) => String.fromCharCode(i + 97)))
.concat([...Array(10)].map((x, i) => `${i}`));
console.log(`Your id: ${createRandomId(10)}`);
function createRandomId(len) {
let characters = alphabetAndNumbers();
console.log(`[characters] initial ${characters.join("")}`);
//retrieve characters to exclude from the template element and split it to an array
const excludes = document.querySelector("#excludes").content.textContent.split("");
// filter initial characters array to exclude the characters in [excludes]
// now [characters] is an array too
characters = characters.filter(c => !~excludes.indexOf(c));
console.log(`excluded ${excludes.join("")}`)
console.log(`[characters] now ${characters.join("")}`);
// create an array with length [len], map characters (pseudo random) into it
// and return the joined array
return [...Array(len)]
.map(v => characters[Math.floor(Math.random() * characters.length)])
// ^ characters is array, so you can pick an element from it
.join("");
}
// easier may be to initially use a subset
const createRandomIdSimple = (len, chars) => [...Array(len)]
.map(v => chars[Math.floor(Math.random() * chars.length)])
.join("");
const chars4Id = document.querySelector("#chars4RandomId").content.textContent.split("");;
console.log(`Your id from createRandomSimple: ${createRandomIdSimple(10, chars4Id)}`);
<template id="excludes">DWX23Aal0gn</template>
<template id="chars4RandomId">BCEFGHIJKLMNOPQRSTUVYZbcdefhijkmopqrstuvwxyz1456789</template>
Bonus: rewritten to a factory function for creating random Id's
const randomId = RandomIdFactory();
const log = Logger();
log(`Lets create 25 pseudo random id's of length 32`,
`without "l" (lowercase L) and "0" (zero):\n`,
[...Array(25)].map(x => randomId(32, "l0")).join("\n"));
function RandomIdFactory() {
const characters = [...Array(26)]
.map((x, i) => String.fromCharCode(i + 65))
.concat([...Array(26)].map((x, i) => String.fromCharCode(i + 97)))
.concat([...Array(10)].map((x, i) => `${i}`));
return (len, excludes) => {
const chars = excludes &&
characters.filter(c => !~excludes.indexOf(c)) ||
characters;
return [...Array(len)]
.map(v => chars[Math.floor(Math.random() * chars.length)])
.join("");
};
}
function Logger() {
const logEl = document.querySelector("#log") || (() => {
document.body.append(Object.assign(document.createElement('pre'), {id:"log"}));
return document.querySelector("#log");
})();
return (...strs) => strs.forEach(s => logEl.textContent += `${s}\n`);
}
I am trying to find a word from consecutive strings inside an array and I am stuck at the moment.
For example: array = ['w', 'r', 'a', 'p', 'p', 'l', 'e', 'f', 'k', 'l']; I want to make a function that will return true if the word 'apple' is inside this array. Strings need to be consecutive.
array1 = ['w', 'r', 'a', 'p', 'l', 'p', 'e', 'f', 'k', 'l']; function for this kind of strings with no consecutive 'apple' strings should return false.
Can you help please?
array = ["w", "r", "a", "p", "p", "l", "e", "f", "k", "l"];
console.log(array.toString().replace(/,/g,"").indexOf("apple")>-1);
One approach would be traverse your array, and get substrings of length that equals the length of the matching substring, and compare the substring with the matching substring
for (int i=0; i<array.length-matching.length; i++) {
if (array.substr(i, i+matching.length) == matching) return true;
} return false;
Try this:
var array = ['w', 'r', 'a', 'p', 'p', 'l', 'e', 'f', 'k', 'l'];
function findWord(arr, word) {
return arr.join('').indexOf(word) !== -1;
}
// test
console.log('apple: ', findWord(array, 'apple'))
console.log('dog: ', findWord(array, 'dog'))
check this function:
function hasWord(inputSourceList, inputWord) {
return inputSourceList.join('').indexOf(inputWord) > -1;
};
With Array.join(), String.replace() and String.indexOf() functions:
var contains_word = function(arr, w) {
return arr.join('').replace(new RegExp('[^' + w + ']', 'g'), '')
.indexOf(w) !== -1;
}
console.log(contains_word(['w', 'r', 'a', 'p', 'l', 'p', 'e', 'f', 'k', 'l'], 'apple'));
console.log(contains_word(['w', 'r', 'a', 'p', 'p', 'l', 'e', 'f', 'k', 'l'], 'apple'));
You can use a combination of Array.every(), and Array.indexOf() to check if all letters are found in the correct order:
const findWordInArray = (word, array) => {
let last = -1; // stores the last index found
// iterate the letters of the word
return [...word].every((c) => {
// search for the letter from the last known position + 1 onwards
const index = array.indexOf(c, last + 1);
last = index; // change last to the new found position
return index !== -1;
});
}
const array1 = ['w', 'r', 'a', 'p', 'p', 'l', 'e', 'f', 'k', 'l'];
const array2 = ['w', 'r', 'a', 'p', 'l', 'p', 'e', 'f', 'k', 'l'];
const word = 'apple';
console.log(findWordInArray(word, array1));
console.log(findWordInArray(word, array2));
Here is my code :
String.prototype.escape = function(){
return this.replace(new RegExp("[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]", "g"), "\\$&");
}
String.prototype.replaceAll = function(search, replace){
if(!replace){
return this;
}
return this.replace(new RegExp(search, 'g'), replace);
};
String.prototype.RreplaceAll = function(search_string, replace_string){
if(!replace_string){
return this;
}
return this.replace(new RegExp(replace_string, 'g'), search_string);
};
function encrypt(){
var string = prompt("String to Encrypt : ");
string.escape();
var replace_array = ['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', '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'];
string = string.replaceAll("/", "53/");
string = string.replaceAll("0", "/)\\");
string = string.replaceAll("1", "/!\\");
string = string.replaceAll("2", "/#\\");
string = string.replaceAll("3", "/#\\");
string = string.replaceAll("4", "/$\\");
string = string.replaceAll("5", "/%\\");
string = string.replaceAll("6", "/^\\");
string = string.replaceAll("7", "/&\\");
string = string.replaceAll("8", "/*\\");
string = string.replaceAll("9", "/(\\");
for (var i = 0; i < 52; i++){
if (i < 9) {
new_string = "0" + String(i + 1);
} else {
new_string = String(i + 1);
}
string = string.replaceAll(replace_array[i], new_string + "/");
}
document.getElementById("text").innerHTML = string;
}
function decrypt(){
var string = prompt("String to Decrypt : ");
string.escape();
var replace_array = ['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', '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'];
for (var i = 0; i < 52; i++){
if (i < 9) {
old_string = "0" + String(i + 1);
} else {
old_string = String(i + 1);
}
old_string = old_string + "/";
string = string.replaceAll(old_string, replace_array[i]);
}
string = string.RreplaceAll("/", "53/");
string = string.RreplaceAll("0", "/)\\");
string = string.RreplaceAll("1", "/!\\");
string = string.RreplaceAll("2", "/#\\");
string = string.RreplaceAll("3", "/#\\");
string = string.RreplaceAll("4", "/$\\");
string = string.RreplaceAll("5", "/%\\");
string = string.RreplaceAll("6", "/^\\");
string = string.RreplaceAll("7", "/&\\");
string = string.RreplaceAll("8", "/*\\");
string = string.RreplaceAll("9", "/(\\");
document.getElementById("text").innerHTML = string;
}
However when I decrypt() with any string, it gave an error at console :
SyntaxError: unmatched ) in regular expression
What can I do? I've tried doing something to escape the string with special characters, but it still doesn't work. Where's the problem? Please help.
You are trying to use "/)\\" as a regular expression, in:
string = string.RreplaceAll("0", "/)\\");
but ) is a special character in regular expressions. You have to escape the character first, manually ("/\\)\\") or with your .escape method.