I'm trying to set select a random item from an array. Once selected, it needs to be removed from the array so it does not get selected again. Finally, once the array is emptied, the process needs to restart. I'm trying to do this using sessionStorage because I need to keep track of which random item gets selected.
// Get array from sessionStorage
myArray = JSON.parse(sessionStorage.getItem("array"));
// If array does not exist in sessionStorage, set it
if (myArray === null) {
sessionStorage.setItem("array", JSON.stringify(["apple", "orange", "banana"]));
// If array exists in sessionStorage, use it to get random item and empty it from array
} else {
var randomItem = myArray[Math.floor(Math.random() * myArray.length)];
console.log(randomItem);
console.log(myArray.splice(randomItem, 1));
}
My JSFiddle can be seen here.
Edit: Updated my work here. Eventually the array is cleared out and restarts.
This probably will not run in this sandbox (use of localstore), but I think it should work if you tried it.
// -------------------------------
// see: http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
// -------------------------------
function _shuffle (array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
// -------------------------------
// -------------------------------
// Get the next "random" item.
// -------------------------------
var randomItem = (function(allItems){
var _key = "array";
var _currentItems = [];
try {
_currentItems = JSON.parse(localStorage.getItem(_key) || "[]");
} catch (e) {
_currentItems = [];
}
if (!Array.isArray(_currentItems) || _currentItems.length === 0 ) {
console.log("resetting");
_currentItems = _shuffle(allItems.slice());
}
var _selectedItem = _currentItems.pop();
localStorage.setItem(_key, JSON.stringify(_currentItems));
return _selectedItem;
})(["apple", "orange", "banana"]);
// -------------------------------
console.log(randomItem);
A more bare bones version [ with _shuffle() from above ] might be just:
var nextItem = (function(all){
var _key = "array";
var _current = JSON.parse(localStorage.getItem(_key) || "[]");
if (_current.length === 0) { _current = _shuffle(all.slice()); }
var _selected = _current.pop();
localStorage.setItem(_key, JSON.stringify(_current));
return _selected;
})(["apple", "orange", "banana"]);
I think the problem you are having is caused by the fact that you are passing the value you get from the array the the splice() function when it is actually expecting an index. Checkout the docs page. so what you would do instead is:
// Get array from sessionStorage
myArray = JSON.parse(sessionStorage.getItem("array"));
// If array does not exist in sessionStorage, set it
if (myArray === null) {
sessionStorage.setItem("array", JSON.stringify(["apple", "orange", "banana"]));
// If array exists in sessionStorage, use it to get random item and empty it from array
} else {
//get random index of item to remove
var randomIndex = Math.floor(Math.random() * myArray.length);
//remove the item at that index
myArray.splice(randomIndex, 1); //this returns an array containing the removed item, so you can capture it if you like
}
Related
So i'm using a trivia game api to request trivia questions for a webapp i'm programming. I've figured out how to randomize it but i can't figure out how to not make it repeat options.
function useApiData(data){
let answers= [data.results[0].correct_answer, data.results[0].incorrect_answers[0], data.results[0].incorrect_answers[1], data.results[0].incorrect_answers[2]]
document.querySelector("#category").innerHTML = `Category: ${data.results[0].category}`
document.querySelector("#difficulty").innerHTML = `Difficulty: ${data.results[0].difficulty}`
document.querySelector("#question").innerHTML = `Question: ${data.results[0].question}`
document.querySelector("#answer1").innerHTML = `${answers[Math.floor(Math.random()*answers.length)]}`
document.querySelector("#answer2").innerHTML = `${answers[Math.floor(Math.random()*answers.length)]}`
document.querySelector("#answer3").innerHTML = `${answers[Math.floor(Math.random()*answers.length)]}`
document.querySelector("#answer4").innerHTML = `${answers[Math.floor(Math.random()*answers.length)]}`
}
So to make it work as you expected you should pop each selected item in the array out, then make a new choice between existing ones.
It should be something like this:
function randomItemWithNoRepetition(array) {
let copy = Array.from(array); // Create a copy of input array
return function() {
if (copy.length < 1) { copy = Array.from(array); } // This line exist to create copy and make a new array from actual array whenever all possible options are selected once
const index = Math.floor(Math.random() * copy.length); // Select an index randomly
const item = copy[index]; // Get the index value
copy.splice(index, 1); // Remove selected element from copied array
return item; // Return selected element
};
}
const chooseFromArray = randomItemWithNoRepetition(['Foo', 'Bar', 'FU', 'FooBar' ]); // The input of this function should be the array of your answers. I just add dummy data as an input of function for more illustration.
document.querySelector("#answer1").innerHTML = `${chooseFromArray()}`; // "Bar"
document.querySelector("#answer2").innerHTML = `${chooseFromArray()}`; // "Foo"
document.querySelector("#answer3").innerHTML = `${chooseFromArray()}`; // "FU"
document.querySelector("#answer4").innerHTML = `${chooseFromArray()}`; // "FooBar"
Javascript arrays have a method called sort() which sorts all the answers given a specified function, a negative number sends the element back in the array and a positive number sends it forward, so given that you can make a quick function to sort an array randomly like so:
function sortArrayRandomly(array) {
return array.concat().sort(() => 0.5 - Math.random());
}
this function will sort your array in a random order, you can then use it in your code like so:
function useApiData(data){
let answers = sortArrayRandomly([data.results[0].correct_answer, data.results[0].incorrect_answers[0], data.results[0].incorrect_answers[1], data.results[0].incorrect_answers[2]]);
document.querySelector("#category").innerHTML = `Category: ${data.results[0].category}`
document.querySelector("#difficulty").innerHTML = `Difficulty: ${data.results[0].difficulty}`
document.querySelector("#question").innerHTML = `Question: ${data.results[0].question}`
document.querySelector("#answer1").innerHTML = `${answers[0]}`
document.querySelector("#answer2").innerHTML = `${answers[1]}`
document.querySelector("#answer3").innerHTML = `${answers[2]}`
document.querySelector("#answer4").innerHTML = `${answers[3]}`
}
A good way to randomize an array is called the Fisher-Yates shuffle algorithm.
You can use it as follows.
(Run the snippet multiple times to see that the answers are randomly ordered.)
// Defines the answers and the corresponding HTML elements
let answers = ["JavaScript", "42", "Maybe", "Leroy Jenkins"];
const answerElements = [
document.getElementById("answer1"),
document.getElementById("answer2"),
document.getElementById("answer3"),
document.getElementById("answer4")
];
// Shuffles the answers
randomize(answers);
// Loops through the randomized answers
for(let i = 0; i < answers.length; i++){
// Checks to be sure the property we're assigning to exists
if(answerElements[i] && answerElements[i].textContent){
// Assigns the string to the element's textContent property
answerElements[i].textContent = answers[i];
}
}
// Implements a Fisher-Yates shuffle
function randomize(array){
for(let i = array.length - 1; i > 0; i--){
const index = Math.floor(Math.random() * i);
const tmp = array[index];
array[index] = array[i];
array[i] = tmp;
}
}
<div id="answer1">1</div>
<div id="answer2">2</div>
<div id="answer3">3</div>
<div id="answer4">4</div>
I would like to browse an associative array like a circular list.
First the associative array is defined like this :
array = {item1:array(...), item2:array(...), ...}
When at the first element I browse the array of this element, once arrive at the last element of this array it should passe to the second element and brows it's array, and the same for the last one who must return to the first element.
so I initialize my array as follows:
// Build the associative array
Prot.prototype.additem = function(itemName, itemArray)
{
this.array[itemName] = itemArray; // itemArray is an array
}
// Init the currentItem of the associative array to browse (We don't necessarily start at the first)
Prot.prototype.init = function(itemName)
{
this.currentItem = this.array[itemName];
this.currentItemArray = 0;
}
Prot.prototype.next = function()
{
// here I browse the first array of the first key of my associative array
var index = this.currentItem.indexOf(this.currentItemArray);
index = index +1;
this.currentItemArray = this.currentItem[index];
if (index == (this.currentItemArray.length - 1))
{
// when arrives at the last element of the array of the first key I should pass to the second
return false;
}
else {
return true;
}
}
// I add a set interval at the end so no need for a loop
You'll need an array to know what is the "next" item array. So I would suggest storing the desired order in another array, having just those names.
Here is a possible implementation:
class Prot {
constructor() {
this.itemNames = [];
this.arrays = {};
this.hasData = false;
this.currentIndex = 0;
}
additem(itemName, itemArray) {
if (itemName in this.arrays) throw "duplicate entry";
this.arrays[itemName] = { data: itemArray, index: this.itemNames.length };
this.itemNames.push(itemName); // keep the order
if (itemArray.length) this.hasData = true;
}
init(itemName) {
this.currentItem = this.arrays[itemName];
this.currentIndex = 0;
}
next() {
if (!this.hasData) return;
if (!this.currentItem) this.currentItem = this.arrays[this.itemNames[0]];
var data = this.currentItem.data[this.currentIndex++];
while (this.currentIndex >= this.currentItem.data.length) {
this.currentItem = this.arrays[this.itemNames[(this.currentItem.index+1) % this.itemNames.length]];
this.currentIndex = 0;
}
return data;
}
}
// demo
let obj = new Prot;
// add the arrays:
obj.additem("a", [1, 2, 3]);
obj.additem("b", [4, 5]);
obj.additem("c", [6, 7, 8, 9]);
obj.additem("d", [0]);
// Start at "b":
obj.init("b");
// iterate from there...
for (let i = 0; i < 12; i++) {
console.log(obj.next());
}
There is no such thing as an associative array in JavaScript, but you can use an object instead. A very simple implementation of defining an object and referencing its properties in a circular way would be the following:
// define the object with 6 properties and assiociated values:
var obj={a:123, b:456, c:789, d:666, e:777, f:888};
function getcirc(obj){
// use a "static variable" inside the function:
if(typeof getcirc.i=="undefined") getcirc.i=0;
var keys=Object.keys(obj), k=keys[getcirc.i++%keys.length];
console.log(k,obj[k]);
}
// call the function repeatedly ...
for (var n=0;n<20;n++) getcirc(obj);
I am trying to update a value in the array if it is found, if it isn't then add a new array to it.
Here's some code I have been trying:
var cartItems = {};
var items = []
cartItems.items = items;
$('.proAdd').click(function(){
var name = $(this).attr("data-name");
var price = parseFloat($(this).attr("data-price"));
var quantity = parseInt($(this).attr("data-quantity"));
var item = {"name": name,"price": price,"quantity": quantity}
items.forEach(function(item) {
if (item.name === name) {
item.quantity = 2
return;
}else{
cartItems.items.push(item);
}
});
In this version noting gets pushed. If I take out the else branch then it does update it but also pushes it. I have created a fiddle for this.
Also tried this but it says x.quantity is not defined:
var index = items.findIndex(x => x.name==name)
if (index != -1){
x.quantity = 2
}
else {
cartItems.items.push(item);
}
Because index stores the index of an item, and x is a temporary value which is unavailable after that line. Use find instead, and make sure you're looking at the same items each time:
var item = cartItems.items.find(x => x.name == name);
if (item) {
item.quantity = 2;
} else {
cartItems.items.push(item);
}
Given an array I want to find the largest sub array by the length i.e
var table = [
["Protein",["Grilled Chicken","Lamb"]],
["Fats",["rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr"]],
["Vegatables",["Carrots","Eggs","Milks","Peppers"]]
];
I want it to return ["Carrots","Eggs","Milks","Peppers"]
Heres my code
function findBiggestSubArray(array){
var biggestArrayIndex = 0;
for(var i=0;i<array.length;i++){
if(i === (array.length-1)){
//We have reached the end of the array then return the array
console.log("Reached the End");
return array[biggestArrayIndex];
} else {
if(!array[biggestArrayIndex][1].length >= array[i][1].length){
biggestArrayIndex = i;
}//End of Inner else block
}//End of Outer else block
}//End of forloop
}
General solution, to find the most largest array in an array-structure:
I would do it with recursion, so the most biggest Array will be found, in any depth..
/**
* array -> The array to check,
* biggestArray -> The most biggestArray found so far
*/
function findBiggestArray(array, biggestArray){
biggestArray = biggestArray || [];
if (array.length > biggestArray.length)
biggestArray = array;
for (var i = 0; i < array.length; i++) {
if (array[i] instanceof Array)
biggestArray = findBiggestArray(array[i],biggestArray)
}
return biggestArray;
}
var multiArray = [
["1", "2", ["234", "334"]],
[1,2,3,4,5, [1,2,3,4,5,6,7,7]]
]
var biggest = findBiggestArray(multiArray)
console.log(biggest)
// This also works!
console.log(findBiggestArray([1, [1,2,3]]))
Oneliner for this special case
// Sort the array by the length of the subarray at position 1, and return the first item
var category = table.sort(function(a, b) { return b[1].length - a[1].length })[0]
// ES6-Syntax
var category = table.sort((a, b) => b[1].length - a[1].length)[0]
category // => ["CategoryName", [ITEMS..]]
I would do this way (see the comments in the code for explanation):
var table = [
["Protein", ["Grilled Chicken", "Lamb"]],
["Fats", ["rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr"]],
["Vegatables", ["Carrots", "Eggs", "Milks", "Peppers"]]
];
function findBiggestSubArray (array) {
// Initialise empty array.
var bigSubArray = ["", []];
// Loop through the given array.
for (var i = 0; i < array.length; i++) {
// Check if the current biggest one is bigger than the saved array.
if (array[i][1].length > bigSubArray[1].length) {
// If bigger, replace it with current array.
bigSubArray = array[i];
}
}
// Return the biggest sub array.
return bigSubArray[1];
}
console.log(findBiggestSubArray(table));
I have two arrays which are
product_id = [5,5,10,15,5,15,22]
product_qty = [58,40,120,100,98,100,50]
(I have stored to array as sequence from table. id and quantity orders are same as i mentioned above.)
I want to calculate the same id's total quantity with their id. Result should be
result_id = [5,10,15,22] //no duplicates
result_qty = [196,120,200,50] //sum to same id's quantity
how to solve this issue in javascript?
One possible solution (keeping the two array solution as specified in the question, although you may want to look into a hash as specified by Vineswaran in the comments) is to traverse the first array (with the ids) and push the value if it doesn't exist in the index array, or add the value if it exists in the index array, like this:
var product_id = [5,5,10,15,5,15,22];
var product_qty = [58,40,120,100,98,100,50];
var result_id = [];
var result_qty = [];
// traverse the product ids array
$.each(product_id, function(idx, val) {
// check if that product id had a previous instance
var auxIdx = $.inArray(val, result_id)
if (auxIdx >= 0) {
// if it did, add the quantities
result_qty[auxIdx] += product_qty[idx];
} else {
// if it didn't, push both id and quantity into the result arrays
result_id.push(val);
result_qty.push(product_qty[idx]);
}
});
console.log(result_id);
console.log(result_qty);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
You can see it on this JSFiddle too: http://jsfiddle.net/pmkLcLdd/
I don't have your sample data. So, i have modified your code in the comment.
var store_product = {};
$(data).each(function(did,value){
var product_place_id = value.product_place_id_primary;
var ids = getProductAndPlaceId(product_place_id);
var item_quantity = store_product[ids[0]];
if (item_quantity) {
store_product[ids[0]] = (item_quantity + value.quantity);
} else {
store_product[ids[0]] = value.quantity;
}
});
store_product hash will have your expected result. You can convert it into array or anything as per your needs.
you don't need jquery for this
var product_id = [5,5,10,15,5,15,22]
var product_qty = [58,40,120,100,98,100,50]
var result_id = product_id.slice(); //Copy arrays
var result_qty = product_qty.slice()
var i = result_id.length;
while(i > 0){
var id = result_id.shift(); //remove first element
--i;
var sum = result_qty.shift(); //init sum count
var index = result_id.indexOf(id, 0); //find next match of element
while(index != -1){
result_id.splice(index, 1); //remove element in index
--i;
sum += result_qty.splice(index, 1)[0]; //index 0, since splice return a list with length 1
index = result_id.indexOf(id,index);
}
result_id.push(id); //add to end
result_qty.push(sum);
}
console.log(result_id);
console.log(result_qty);
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
I think an object would be better suited for what you want as a result, this way, you can easily relate an id to its quantity, with the id being the key:
var product_id = [5,5,10,15,5,15,22],
product_qty = [58,40,120,100,98,100,50],
result_qty = {};
product_qty.forEach(function (qty, i) {
var indexVal = result_qty[product_id[i]] || 0;
result_qty[product_id[i]] = indexVal + qty;
});
console.log(result_qty);
// Logs Object {5: 196, 10: 120, 15: 200, 22: 50}
console.log(result_qty[5]);
// Logs 196
//////////////////////////////////////////////////////////////////
// * However, if you really want both, the ids and quantities in
// * array format, then it's just a matter of running this,
// * after the previous code:
var tmp = [],
result_id = [];
// * (looping through the object)
for(var prop in result_qty) {
if(result_qty.hasOwnProperty(prop)) {
tmp.push(result_qty[prop]);
result_id.push(parseInt(prop, 10));
}
}
result_qty = tmp;
console.log(result_id);
// Logs [196, 120, 200, 50]
console.log(result_qty);
// Logs [5, 10, 15, 22]
I've included a way to get the arrays anyway, so you have both options.