I want to generate unique ID - javascript

I want to generate unique ID in JavaScript. I have tried uuid npm package, it's good but it's not what I want.
For example what I get as a result from generating unique ID from uuid package is
9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
Is there any way to make specific format as I want.
For example I want my ID to look like this
XZ5678
In this example format is two uppercase letters and 4 numbers.
That's it, I'm looking for answer and thank you all in advance.

If you're just looking to generate a random sequence according to that pattern, you can do so relatively easily. To ensure it's unique, you'll want to run this function and then match it against a table of previously generated IDs to ensure it has not already been used.
In my example below, I created two functions, getRandomLetters() and getRandomDigits() which return a string of numbers and letters the length of the argument passed to the function (default is length of 1 for each).
Then, I created a function called generateUniqueID() which generates a new ID according to the format you specified. It checks to see if the ID already exists within a table of exiting IDs. If so, it enters a while loop which loops until a new unique ID is created and then returns its value.
const existingIDs = ['AA1111','XY1234'];
const getRandomLetters = (length = 1) => Array(length).fill().map(e => String.fromCharCode(Math.floor(Math.random() * 26) + 65)).join('');
const getRandomDigits = (length = 1) => Array(length).fill().map(e => Math.floor(Math.random() * 10)).join('');
const generateUniqueID = () => {
let id = getRandomLetters(2) + getRandomDigits(4);
while (existingIDs.includes(id)) id = getRandomLetters(2) + getRandomDigits(4);
return id;
};
const newID = generateUniqueID();
console.log(newID);

Not sure why you want this pattern but you could do like this:
const { floor, random } = Math;
function generateUpperCaseLetter() {
return randomCharacterFromArray('ABCDEFGHIJKLMNOPQRSTUVWXYZ');
}
function generateNumber() {
return randomCharacterFromArray('1234567890');
}
function randomCharacterFromArray(array) {
return array[floor(random() * array.length)];
}
const identifiers = [];
function generateIdentifier() {
const identifier = [
...Array.from({ length: 2 }, generateUpperCaseLetter),
...Array.from({ length: 4 }, generateNumber)
].join('');
// This will get slower as the identifiers array grows, and will eventually lead to an infinite loop
return identifiers.includes(identifier) ? generateIdentifier() : identifiers.push(identifier), identifier;
}
const identifier = generateIdentifier();
console.log(identifier);

They way of what you are suggesting be pretty sure you are going to get duplicates and collitions, I strongly suggest go with uuid.
Also probably you can find this useful: https://www.npmjs.com/package/short-uuid
Or if you want to continue with your idea this could be helpful: Generate random string/characters in JavaScript

Related

Javascript Compare two arrays based on partial match and update to fully match

I'm working on a project in Node.js (Foundry Virtual Table Top), and I have two arrays. First is a list of entries, the second is the same list, but with indexing numbers prefixed to it. I need to match the two, based on the name, and update the first list to include the same numbering.
Example of 1st list:
Early Life
Circumstances of Birth
Family
Region
...
Example of 2nd list:
1.3. Early Life
1.3.1. Circumstances of Birth
1.3.2. Family
1.3.3. Region
So I want "Early Life" to be updated to "1.3. Early Life"
I have the base of it done, along with the regex I need, but I'm not sure how to actually compare, match, and then update based on the partial matches. Any help would be greatly appreciated, I have very little experience with javascript.
/** Takes a compendium of journals and matches then replaces names to those of an imported list prepended with index numbers
* New naming convention == "#.##... TEXT"
* Eg. "Special Abilities" -> "2.01.2. Special Abilities"
*
* 1. put the new name list in an array
* 2. iterate through the compendium, get index or contents
* 3. compare the entries name value vs new list(array), regex'd to remove the #s and . prior to the name, and set an update array with the new name
* 4. update the compendium
*/
//read text file of new names
let f = await fetch("/test_list.txt")
let txt = await f.text()
// Convert to array, split by line
let updatedNames = txt.toString().split("\n");
// Compendium to Update
const compendiumLabel = "Gamemastery";
(async ()=>{
const p = game.packs.entries.find(e => e.metadata.label === compendiumLabel)
// Array of current journal entries (filtering out Compendium Folders)
const currentNames = p.index.filter(x => x.name != '#[CF_tempEntity]').map(i=>{
return { name : i.name };
});
// Compare currentNames to updatedNames (regex'd to remove starting numbers and .)
// regex that excludes the numbering "#.#.#. " from updatedNames
let regex = new RegExp('[^(\d+.)+\s].*', 'g')
// update compendium
})();
Maybe something like this:
const notIndexed = `Early Life
Circumstances of Birth
Family
Region`.split('\n');
const indexed = `1.3. Early Life
1.3.1. Circumstances of Birth
1.3.2. Family
1.3.3. Region`.split('\n');
const regexp = /^((?:\d.)+) +(.+)/;
const mapping = new Map(
indexed.map((line) => {
const [, index, title] = line.match(regexp);
return [title, index];
})
);
const reIndexed = notIndexed.map(
(line) => {
if (mapping.has(line)) return `${mapping.get(line)} ${line}`;
return line;
}
).join('\n');
console.log(reIndexed);

Are there ways of easily sorting a list of objects like this in Javasript?

I have a Node class
class Node:
def __init__(self, move = None, parent = None, state = None):
self.move = move
self.parentNode = parent # "None" for the root node
self.childNodes = []
self.wins = 0
self.visits = 0
self.untriedMoves = state.GetMoves() # future child nodes
self.playerJustMoved = state.playerJustMoved # the only part of the state that the Node needs later
def UCTSelectChild(self):
""" Use the UCB1 formula to select a child node. Often a constant UCTK is applied so we have
lambda c: c.wins/c.visits + UCTK * sqrt(2*log(self.visits)/c.visits to vary the amount of
exploration versus exploitation.
"""
s = sorted(self.childNodes, key = lambda c: c.wins/c.visits + sqrt(2*log(self.visits)/c.visits))
return s
I have a list of these Node objects.
In Python I can easily sort like so..
s = sorted(self.childNodes, key = lambda c: c.wins/c.visits + sqrt(2*log(self.visits)/c.visits))
Best way to do this in Javascript? This is my first day using Javascript..
You can use the sort() method of the Array.
array = [...];
array = array.sort();
This will sort the array based on the default comparison logic. If you want to provide your own comparison logic, you can just pass a compare function as an argument. Unlike Python's key where you consume just one parameter, the compare function provides firstElement and secondElement as the parameters. So, you might do something like this:
array = array.sort((firstEl, secondEl) => {
let first = firstEl.wins / firstEl.visits + sqrt(2 * Math.log(firstEl.visits)/firstEl.visits);
let second = secondEl.wins / secondEl.visits + sqrt(2 * Math.log(secondEl.visits)/secondEl.visits);
return first - second;
});
Surely, this seems a bit more verbose but that's how it is.

How do I loop over a VERY LARGE 2D array without causing a major performace hit?

I am attempting to iterate over a very large 2D array in JavaScript within an ionic application, but it is majorly bogging down my app.
A little background, I created custom search component with StencilJS that provides suggestions upon keyup. You feed the component with an array of strings (search suggestions). Each individual string is tokenized word by word and split into an array and lowercase
For example, "Red-Winged Blackbird" becomes
['red','winged','blackbird']
So, tokenizing an array of strings looks like this:
[['red','winged','blackbird'],['bald','eagle'], ...]
Now, I have 10,000+ of these smaller arrays within one large array.
Then, I tokenize the search terms the user inputs upon each keyup.
Afterwards, I am comparing each tokenized search term array to each tokenized suggestion array within the larger array.
Therefore, I have 2 nested for-of loops.
In addition, I am using Levenshtein distance to compare each search term to each element of each suggestion array.
I had a couple drinks so please be patient while i stumble through this.
To start id do something like a reverse index (not very informative). Its pretty close to what you are already doing but with a couple extra steps.
First go through all your results and tokenize, stem, remove stops words, decap, coalesce, ects. It looks like you've already done this but i'm adding an example for completion.
const tokenize = (string) => {
const tokens = string
.split(' ') // just split on words, but maybe rep
.filter((v) => v.trim() !== '');
return new Set(tokens);
};
Next what we want to do is generate a map that takes a word as an key and returns us a list of document indexes the word appears in.
const documents = ['12312 taco', 'taco mmm'];
const index = {
'12312': [0],
'taco': [0, 1],
'mmm': [2]
};
I think you can see where this is taking us... We can tokenize our search term and find all documents each token belongs, to work some ranking magic, take top 5, blah blah blah, and have our results. This is typically the way google and other search giants do their searches. They spend a ton of time in precomputation so that their search engines can slice down candidates by orders of magnitude and work their magic.
Below is an example snippet. This needs a ton of work(please remember, ive been drinking) but its running through a million records in >.3ms. Im cheating a bit by generate 2 letter words and phrases, only so that i can demonstrate queries that sometimes achieve collision. This really doesn't matter since the query time is on average propionate to the number of records. Please be aware that this solution gives you back records that contain all search terms. It doesn't care about context or whatever. You will have to figure out the ranking (if your care at this point) to achieve the results you want.
const tokenize = (string) => {
const tokens = string.split(' ')
.filter((v) => v.trim() !== '');
return new Set(tokens);
};
const ri = (documents) => {
const index = new Map();
for (let i = 0; i < documents.length; i++) {
const document = documents[i];
const tokens = tokenize(document);
for (let token of tokens) {
if (!index.has(token)) {
index.set(token, new Set());
}
index.get(token).add(i);
}
}
return index;
};
const intersect = (sets) => {
const [head, ...rest] = sets;
return rest.reduce((r, set) => {
return new Set([...r].filter((n) => set.has(n)))
}, new Set(head));
};
const search = (index, query) => {
const tokens = tokenize(query);
const canidates = [];
for (let token of tokens) {
const keys = index.get(token);
if (keys != null) {
canidates.push(keys);
}
}
return intersect(canidates);
}
const word = () => Math.random().toString(36).substring(2, 4);
const terms = Array.from({ length: 255 }, () => word());
const documents = Array.from({ length: 1000000 }, () => {
const sb = [];
for (let i = 0; i < 2; i++) {
sb.push(word());
}
return sb.join(' ');
});
const index = ri(documents);
const st = performance.now();
const query = 'bb iz';
const results = search(index, query);
const et = performance.now();
console.log(query, Array.from(results).slice(0, 10).map((i) => documents[i]));
console.log(et - st);
There are some improvements you can make if you want. Like... ranking! The whole purpose of this example is to show how we can cut down 1M results to maybe a hundred or so canidates. The search function has some post filtering via intersection which probably isn't what you want you want but at this point it doesn't really matter what you do since the results are so small.

How to use reduce and the ramda "hex2color" function to count list of hex values than have r in their color name?

"Use reduce and the hex2color function to count list of hex values than have r in their name";
My current attempt is below. The first piece I know needs to be fixed is the filter function. I need to be able to filter out any colors that have the letter "r", but cannot seem to find a way to easily fit that into the filter function. It could easily be a syntax issue as I think I am asking the filter to find any strings that === "r", even though I am trying to use "contains" to solve that and have it check the whole color word.
Once the filter function is working, I assume the next step is to simply use the reduce function, then compose them together. ( I could be way off off, however).
I am quite new to programming, any insight is extremely welcome. Thanks!!
const exercise3 = _ => {
const hexes = ["#0000ff", "#f5f5dc", "#cd853f", "#663399", "#ffa500"];
const letter = "r";
const mapper = hex2color;
console.log(map(mapper, hexes)); //blue,beige,peru,rebeccapurple,orange
const filterer = el => contains(hex2color(el), letter);
console.log(filter(filterer, hexes)); //yields nothing, I assume to using the filter wrong with "r".
const reducer = (acc, el) => acc + 1;
const mappedFn = map(mapper);
const filtererFn = filter(filterer);
const reducerFn = reduce(reducer, 0);
const composedFn = compose(reducerFn, filtererFn, mappedFn);
return composedFn(hexes);
};

Checking an input against a specific array string

I am trying to create a quiz that randomly selects a question from pool of questions in an array, which is answered in an input box that is to be checked against the corresponding answer string in the array. I used math.floor(math.random() *); to get my random number. The random number is intended to be used to find both the question and answer, which are arranged in order to correspond to one another, e.g. ['question1','question2'] and ['answer1','answer2'].
I am having difficulty with trying to get my input to properly be checked against the corresponding answer value from the array. I am fairly novice at Javascript, so I am not sure as to how to do this. I tried using the document.getElementById command to compare the two. I suspect it has something to do with the fact that ansNum doesn't get the value of questNum because of the fact that questNum is only given its value inside the generateQuiz function. (I realize ansNum is likely redundant, but I was just playing around to see if anything would happen)
Javascript:
const questions = ['What do young Roman males wear?','Who is the Roman god of the smith?','Who is the 6th king of Rome?'];
const answers = ['toga praetexta','vulcan','servius tullius'];
function getQuestNum() {
questNum = Math.floor(Math.random() * 3);
};
function getAnsNum() {
ansNum = questNum();
}
function generateQuiz() {
getQuestNum();
document.getElementById("question").innerHTML = questions[questNum];
};
function checkCorrect() {
getAnsNum();
if (answer[ansNum] = document.getElementById("input").innerHTML) {
document.getElementById("verification").innerHTML = "Correct!";
}
};
Codepen Link
An image of the code
Based on your code, I fixed it with some changes. It is not the best way to do this i think. I posted the js part here.
const questions = ['What do young Roman males wear?','Who is the Roman god of the smith?','Who is the 6th king of Rome?'];
const answers = ['toga praetexta','vulcan','servius tullius'];
var questNum;
function getQuestNum() {
questNum = Math.floor(Math.random() * 3);
};
function getAnsNum() {
ansNum = questNum;
}
function generateQuiz() {
getQuestNum();
document.getElementById("question").innerHTML = questions[questNum];
};
function checkCorrect() {
getAnsNum();
if (answers[ansNum] = document.getElementById("input").value) {
document.getElementById("verification").innerHTML = "Correct!";
}
};
First you need a global variable questNum then you can use it in all of your functions.
The function getAnsNum() is redundant, at least i think so, just use questNum in your checkCorrect() function.
For getElementByID function, insert an ID attribute to your input
<input id="input" type="text" name="input">
For input, if you want to take the value of the input field, use document.getElementById("input").value instead of innerHTML.
If you not sure about any result, console.log it or use Chrome dev debug tool to check the result. In the checkCorrect function, your array name should be answers instead of answer.
Shorter ver:
const questions = ['What do young Roman males wear?','Who is the Roman god of the smith?','Who is the 6th king of Rome?'];
const answers = ['toga praetexta','vulcan','servius tullius'];
var questNum;
function getQuestNum() {
questNum = Math.floor(Math.random() * 3);
};
function generateQuiz() {
getQuestNum();
document.getElementById("question").innerHTML = questions[questNum];
};
function checkCorrect() {
if (answers[questNum] = document.getElementById("input").value) {
document.getElementById("verification").innerHTML = "Correct!";
}
};
It would be simpler to create an array of objects that each contain both a question and an answer - and create a function that generates your random number and returns the object at the corresponding index.
Then you'll have access to everything you need without worrying about whether or not you can maintain access to the original randomly selected number, or matching up indices between two different arrays.

Categories

Resources