Generating set of random elements with further generation of 'one by one' - javascript

I am generating elements that have random data attributes like so :
generateCards : function(n)
{
var actions = ['press', 'blue-right', 'blue-left', 'red-right', 'red-left'],
i = n,
ran,
actions_cpy = actions.slice();
for (; i--;) {
ran = (Math.random() * actions_cpy.length)|0;
$('#container-game-mobile').prepend(
$('<div>', {
// remove and return a random string from the array
'class': 'game-card-mobile',
'data-action': actions_cpy.splice(ran, 1)[0]
})
);
// load the array backup with values when it is empty
if (actions_cpy.length === 0) {
actions_cpy = actions.slice();
}
}
}
Function works in a way where there are more or less equal amounts of each data atribute from actions array. I initially generate 10 elements so n = 10 due to the nature of application every time an action is performed on a .game-card-mobile I destroy it and need to generate new one so, call above function but now with n = 1 . Issue here is that, I somehow need to call elements that will still differ, so prevent 'blue-right' appearing over and over again.

It's a bit confusing, but I think I get the problem.
You need a function to get your actions, that function will return a random of this array, to this function, pass a param of your last actions randomised and if your random is the same as your last random, call the same function again, it will prevent your problem.

Related

How to update a variable that is returned from a function?

I've been trying to write a go back function. What this function will do is it'll store last two ID number that has been generated and append when there is a new one, delete the first one.
I have this function which creates the IDs and plays the video with that ID.
function newVideo(){
let rando = Math.floor((Math.random() * 3970) + 1);
document.getElementById("vsrc").src = "https://raw.githubusercontent.com/ondersumer07/vinematik-videos/master/vid/" + rando + ".mp4";
document.getElementById("videoEl").load();
return rando;
}
I am returning the rando to use it outside this function, and I can access it outside the function, the problem is, the variable outside the function is not updating everytime newVideo() run.
The code for that goes like this:
let rando = newVideo();
let vidids = [];
if (vidids.length < 2) {
vidids.push(rando)
console.log("added")
} else {
vidids.shift()
console.log("deleted")
};
Basically what this does is to get the returned rando value and push it to the vidids array, delete the first one if there is more than two but it won't, it does not update the let vidids = []; array for some reason. I need it to update everytime the newVideo() function ran.
Also, I want the if to add if there is less then two items in that array and delete from the start of the array if there is more than two items in it. Not really sure if that'll work too.
I can't seem to figure out how to do this, am I doing this whole thing wrong or is there still hope for this function? How am I supposed to write that function?
Edit: I've changed the vidids.length part yet the problem still occur because let rando = newVideo(); doesn't update.
In order to keep the last two Items of an array, you can use something like this.
let vidids = [];
function addToArray(item, array){
array.unshift(item);
return array.slice(0,1);
}
//test
vidids = addToArray(newVideo(), vidids);
vidids =addToArray(newVideo(), vidids);
vidids =addToArray(newVideo(), vidids);
vidids =addToArray(newVideo(), vidids);
vidids =addToArray(newVideo(), vidids);
console.log('Done');
You've made a small mistake that caused your code to not work properly.
The IF condition is intended to check the length of the 'vidids' array,
What actually happens is that it compares the array referance instead of it's length
To fix the issue, add .length after 'vidids' inside of the IF condition.
....
if (vidids.length < 2) {
.....
I figured it out. Basically what I did is storing every number the algorithm creates and then taking one before the last.
Which goes like this:
The algorithm for creating random numbers:
function randomNum() {
let rando = Math.floor((Math.random() * 3970) + 1);
return rando;
};
Then I put this function in a variable:
let videoid = randomNum()
I had another variable called videoids which is above and outside of the randomNum function and is an array:
let videoids = []
After that I stored every number I created with videoid inside videoids by pushing it(This push needs to be inside your function):
videoids.push(videoid);
Okay so I stored all the numbers this way. Now I should take one before the last so I can go to previous video. So I needed to create a function, I used this function which was created by Tadeck, in this thread.
if (!Array.prototype.last) {
Array.prototype.last = function() {
return this[this.length - 2];
};
};
Now I can put that inside of my prevVideo function which looks like this:
function prevVideo() {
document.getElementById("vsrc").src = srcRaw + videoids.last() + ".mp4";
document.getElementById("videoEl").load();
videoids.push(videoids.last());
}
Note: Don't forget to push videoids.last inside your videoids otherwise you can only go to your previous number for once.

How to perform fast search on JSON file?

I have a json file that contains many objects and options.
Each of these kinds:
{"item": "name", "itemId": 78, "data": "Some data", ..., "option": number or string}
There are about 10,000 objects in the file.
And when part of item value("ame", "nam", "na", etc) entered , it should display all the objects and their options that match this part.
RegExp is the only thing that comes to my mind, but at 200mb+ file it starts searching for a long time(2 seconds+)
That's how I'm getting the object right now:
let reg = new RegExp(enteredName, 'gi'), //enteredName for example "nam"
data = await fetch("myFile.json"),
jsonData = await data.json();
let results = jsonData.filter(jsonObj => {
let item = jsonObj.item,
itemId = String(jsonObj.itemId);
return reg.test(item) || reg.test(itemId);
});
But that option is too slow for me.
What method is faster to perform such search using js?
Looking up items by item number should be easy enough by creating a hash table, which others have already suggested. The big problem here is searching for items by name. You could burn a ton of RAM by creating a tree, but I'm going to go out on a limb and guess that you're not necessarily looking for raw lookup speed. Instead, I'm assuming that you just want something that'll update a list on-the-fly as you type, without actually interrupting your typing, is that correct?
To that end, what you need is a search function that won't lock-up the main thread, allowing the DOM to be updated between returned results. Interval timers are one way to tackle this, as they can be set up to iterate through large, time-consuming volumes of data while allowing for other functions (such as DOM updates) to be executed between each iteration.
I've created a Fiddle that does just that:
// Create a big array containing items with names generated randomly for testing purposes
let jsonData = [];
for (i = 0; i < 10000; i++) {
var itemName = '';
jsonData.push({ item: Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) });
}
// Now on to the actual search part
let returnLimit = 1000; // Maximum number of results to return
let intervalItr = null; // A handle used for iterating through the array with an interval timer
function nameInput (e) {
document.getElementById('output').innerHTML = '';
if (intervalItr) clearInterval(intervalItr); // If we were iterating through a previous search, stop it.
if (e.value.length > 0) search(e.value);
}
let reg, idx
function search (enteredName) {
reg = new RegExp(enteredName, 'i');
idx = 0;
// Kick off the search by creating an interval that'll call searchNext() with a 0ms delay.
// This will prevent the search function from locking the main thread while it's working,
// allowing the DOM to be updated as you type
intervalItr = setInterval(searchNext, 0);
}
function searchNext() {
if (idx >= jsonData.length || idx > returnLimit) {
clearInterval(intervalItr);
return;
}
let item = jsonData[idx].item;
if (reg.test(item)) document.getElementById('output').innerHTML += '<br>' + item;
idx++;
}
https://jsfiddle.net/FlimFlamboyant/we4r36tp/26/
Note that this could also be handled with a WebWorker, but I'm not sure it's strictly necessary.
Additionally, this could be further optimized by utilizing a secondary array that is filled as the search takes place. When you enter an additional character and a new search is started, the new search could begin with this secondary array, switching to the original if it runs out of data.

Looping through a series of GET requests

I have a get request that looks for a specific ID within a tree, and then pulls back the value from that ID. I need to loop through a series of these get requests, each with a similar ID (each ID increases in value by one).
I have created a standard loop using hard coded values but I'm struggling to set the variable based on dynamic values coming out of the tree.
For example, I can set a variable like this:
var cars = [entry.get('sub_menu.sub_menu_link.0.title'), entry.get('sub_menu.sub_menu_link.1.title'), entry.get('sub_menu.sub_menu_link.2.title')];
This grabs all the values from these areas of the tree.
But I don't know how many of these there will be so I can't hard code it in this way. I need to be able to replace 0, 1 and 2 in those values with a loop that adds a new get request and increases the integer between "link." and ".title" each time.
Expected result would be to add as many get requests in to the variable as it finds, with the integer increased for each request, until it finds no more.
Full example code with hard coded get requests is below (which won't actually work because the tree isn't being pulled in. For example purposes only):
Query.fetch()
.then(function success(entry) {
var subMenu = [entry.get('sub_menu.sub_menu_link.0.title'), entry.get('sub_menu.sub_menu_link.1.title'), entry.get('sub_menu.sub_menu_link.2.title')];
var text = "";
var i;
for (i = 0; i < subMenu.length; i++) {
text += subMenu[i] + "<br>";
}
document.getElementById("subMenu-container").innerHTML = text;
},
function error(err) {
// err object
});
I'm answering based on three assumptions:
entry.get is synchronous
entry.get returns null or undefined if it couldn't get the string matching the argument we pass it
Although your code is using promises, you want to keep it to ES5-level language features (not ES2015+)
See inline comments:
Query.fetch()
.then(function success(entry) {
// Loop getting titles until we run out of them, put them in `titles`
var titles = [];
var title;
while (true) { // Loop until `break;`
// Use string concat to include the value of `titles.length` (0, 1, ...) in the string
title = entry.get('sub_menu.sub_menu_link.' + titles.length + '.title');
if (title === null || title === undefined) {
break;
}
titles.push(title);
}
// Use `Array.prototype.join` to join the titles together with <br> in-between
document.getElementById("subMenu-container").innerHTML = titles.join("<br>");
}, function error(err) {
// Handle/report error
});

How to pass a function only after an entire array has been read and not for each element?

I'm trying to run a function when reading an array, but instead of running the function to each element, which I'm currently using forEach for, I want to make the script to read the entire array and then pass a function.
What I'm trying to say is this:
data.forEach(movie => {
// Log each movie's title
//console.log(movie.title);
// Check if the userWord matches
if (movie.title.toUpperCase().includes(userWord.toUpperCase())) {
alert("YES");
} else {
alert("NO").
}
});
Let's say my array is: array = ["Aa", "Ba", "Ca", "Da"];
If the user enters: a, then the script would alert("YES") four times, and I want to make it alert just once, at the end of the iteration.
For the same example, if the users enters: B, then the script would first alert("NO") once, then alert("YES"), then alert("YES") 2 times, and I want to make it just alert("YES")once, in the end.
Finally, if the users enters: Ferrari, then the script would alert("NO") four times, and I just want it to alert("NO") at the end.
I tried to make it very clear here, that's why the three "cases" of what is happening.
In the end, I want to know if there is a method that is kinda the opposite of the forEach or the common for. Something that just executes the function after reading the entire array.
Change the alert to a bool variable
Remove else (it would only overwrite any match)
if bool statement outside the loop to perform actions
if you want a list of the results, you should store the names in an array and outside of the loop - print.
see below:
Non-loop method:
data = ["test","hello", "hello1"];
search = "lo";
const matches = data.filter(movie => movie.includes(search));
alert(matches) //array of only matches - only has hello and hello 1
I don't know if there are performance gains against a loop... I suppose you could do a side by side comparison on a large dataset
Loop method:
var matches = "";
data.forEach(movie => {
// Check if the userWord matches
if (movie.title.toUpperCase().includes(userWord.toUpperCase())) {
matches += movie.title + "<br> ";
}
});
if (matches.length > 0)
{
document.getElementById("results").innerHTML = matches;
} else {
alert("No match found");
}
You'll see more customization on the first loop, but I think filtering data first is the way to go.
I think closest what you can get is some. Here is example
let data = ["test","hello", "hello1"];
let userWord = "el";
let res = data.some(movie => movie.toUpperCase().includes(userWord.toUpperCase()));
console.log(res) // prints true- means there was at least one "match", so you can alert
You could use the filter array function to filter array elements that match your criteria and then finally alert only if a match is found. Using this method you could get all the elements that have matched to your userWord. That is, the match array will contain all the possible matches.
var data = ['Aa', 'Bb', 'Cc', 'Dd'];
var flag = false;
var userWord = 'F'
var match = data.filter(movie => movie.indexOf(userWord) !== -1);
if(match.length)
console.log('YES');
else
console.log('NO');
If I understand the question correctly, I believe you want to execute something if a predicate matches at least one of the items in the array (correct me if I'm wrong). For that you can use the some method like so:
if (movies.some((movie) => movie.toUpperCase().includes(userWord.toUpperCase()))) {
alert('YES');
} else {
alert('NO');
}

Appending Different Random Number To URL In Javascript Array On Each Loop

I'm trying (without much success) to create an array which contains slides being loaded into an iframe. One of these frames (/Events.php) uses PHP to query a WordPress database and show 1 post chosen at random. This slide needs to show a different random post every time the array loops through.
My code at them moment is...
<script type="text/javascript">
var frames = Array(
'http://www.example.com/Slide01.php', 5,
'http://www.example.com/Slide02.php', 5,
getRandomUrl(), 5,
'http://www.example.com/Slide04.php', 5
);
var i = 0, len = frames.length;
function getRandomUrl()
{
return "http://www.example.com/Events.php?=" + (new Date().getTime());
}
function ChangeSrc()
{
if (i >= len) { i = 0; } // start over
document.getElementById('myiframe').src = frames[i++];
setTimeout('ChangeSrc()', (frames[i++]*1000));
}
window.onload = ChangeSrc;
</script>
The only trouble is everytime /Events.php is shown it has the same number appended to it so therefore shows the same post in each loop.
I need to append a different number to the /Events.php slide on each loop so it generates different content each time.
I'm starting to think I'm approaching this in totally the wrong way so any help or pointers in the right direction would be appreciated!
Cheers,
Mark.
The issue is you are only calling getRandomUrl() once which is when you defined your array, this means the value will always be the same as its only returned once.
One solution would be to store the function itself in your array like so:
var frames = Array(
'http://www.example.com/Slide01.php', 5,
'http://www.example.com/Slide02.php', 5,
getRandomUrl, 5,
'http://www.example.com/Slide04.php', 5
);
And then call it in ChangeSrc() if its a function
function ChangeSrc()
{
if (i >= len) { i = 0; } // start over
var frame = frames[i++],
isFnc = typeof(frame) == "function";
if(isFnc){
frame = frame();
}
document.getElementById('myiframe').src = frame;
setTimeout(function(){
ChangeSrc()
}, frames[i++]*1000);
}
http://jsfiddle.net/redgg6pq/
A tip would be that you are only calling 'getRandomUrl' once, hence why it's always the same image. You want to call it each time you are in the loop.
I would suggest removing it from the static array, and calling it in the loop - does that make sense? :)
HTH

Categories

Resources