Related
The target is to detect superstring in a set of arrays. In this case it should be 'bal' but I get 'lbal'.
const arr = [
['g', 'l', 'o', 'b', 'a', 'l'],
['b','a','l','l']
]
const res = argv.reduce((acc, val) => acc.filter(elem => val.includes(elem)))
This function just gives ALL duplicates(items that are presented in any array) when I need only the most long duplicate sequence. Any suggestions?
you can create an object that counts how many times an element is present in the array of array
like this
const arr = [
['a', 'b', 'm'],
['g', 'o', 'a', 'b'],
['w', 'o', 'u', 'k', 'a', 'b']
]
const countTimes = data => data.flat().reduce((res, v) => {
return {
...res,
[v]: (res[v] || 0 ) + 1
}
}, {})
const duplicates = data => Object.entries(countTimes(data))
.filter(([v, n]) => n > 1)
.map(([v, n]) => v)
console.log(countTimes(arr))
console.log(duplicates(arr) )
const original = [
['a', 'b', 'm'],
['g', 'o', 'a', 'b'],
['w', 'o', 'u', 'k', 'a', 'b']
]
// The easiest is to split up between unique results and duplicates
let uniqueValues = []
let duplicates = []
// Now we're going to loop every array
original.forEach((arr) => {
// Loop every value inside the array
arr.forEach((value) => {
// Check if we had this value already
if (!uniqueValues.includes(value)) {
uniqueValues.push(value)
} else {
duplicates.push(value)
}
})
})
console.log('Duplicates: ', duplicates)
// If you want remove the duplicates from the duplicates, use set
let uniqueDuplicates = [...new Set(duplicates)]
console.log('Unique duplicates: ', uniqueDuplicates)
If you don't have to know in which array duplicates are, you can use Array.prototype.flat() to get rid of nested arrays, then check simple array for duplicates.
const arr = [
['a', 'b', 'm'],
['g', 'o', 'a', 'b'],
['w', 'o', 'u', 'k', 'a', 'b']
]
const arr2 = arr.flat() // ['a', 'b', 'm', 'g', 'o', 'a', 'b', 'w', 'o', 'u', 'k', 'a', 'b']
const hasDuplicates = new Set(arr2).size !== arr2.length
you can create a tally, to find how many each element globally is duplicated by doing a nested forEach
function findDuplicates(data) {
const map = {};
data.forEach((row) => {
row.forEach((item) => {
if (!map[item]) {
map[item] = 1;
} else [map[item]++];
});
});
return map;
}
You can create a simple counter object (if you know python, this is similar to collections.Counter):
class Counter extends Map {
update(values) {
for (let val of values)
this.set(val, 1 + (this.get(val) ?? 0))
}
}
ARR = [
['a', 'b', 'm'],
['g', 'o', 'a', 'b'],
['w', 'o', 'u', 'k', 'a', 'b']
]
const tally = new Counter()
for (let subArray of ARR)
tally.update(new Set(subArray))
for (let [element, count] of tally)
if (count === ARR.length)
console.log(element)
count === yourArrayOfArrays.length selects elements that appear in all arrays, you can replace it with count > 1 to find any duplicates.
/*
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]);
}
}
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));
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));