How to prevent repeating random numbers in Vue 3 and JavaScript - javascript

I am attempting to build a function that loops through a series of array objects containing names and ids after the array objects have been randomized, then returns a single filtered item to slots.value. So far, my spin function works in terms of looping through the randomized objects. However, the line const index = Math.floor(Math.random() * list.length) occasionally returns the same index number twice in a row. I wish to prevent the random index function from returning the same index number twice in a row. How can I do this?
const slots = ref([])
const names = ref([
{ name: 'Leslie', id: 1 },
{ name: `Ron`, id: 2 },
{ name: 'April', id: 3 },
{ name: 'Andy', id: 4 },
{ name: 'Tom', id: 5 },
{ name: 'Jerry', id: 6 },
])
const sleep = (milliseconds) => {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}
const spin = async () => {
const list = names.value.sort(() => Math.random() - 0.5)
const newArray = []
for (let i = 0; i < list.length; i++) {
const index = Math.floor(Math.random() * list.length)
await sleep(100)
slots.value = list.filter(r => r.id === (index + 1))
}
}

One solution is to re-generate the index if the new value matches the previous one:
let prevIndex = null
const generateRandIndex = max => {
let index
do {
index = Math.floor(Math.random() * max)
} while (index === prevIndex)
prevIndex = index
return index
}
const spin = async () => {
⋮
for (let i = 0; i < list.length; i++) {
const index = generateRandIndex(list.length)
⋮
}
}
demo

Related

Update Google sheet Every 1hr

How can I make this script run and update the google sheet every 1hr. I want new data to append at the bottom not to overwrite the existing data and is there any possibility it will delete the duplicate data automatically on the basis of Column C, deleting old values and leaves new.
function youTubeSearchResults() {
// 1. Retrieve values from column "A".
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const values = sheet.getRange("A2:A" + sheet.getLastRow()).getDisplayValues().filter(([a]) => a);
// 2. Retrieve your current values.
const modifyResults = values.flatMap(([keywords]) => {
const searchResults = JSON.parse(UrlFetchApp.fetch(`https://yt.lemnoslife.com/noKey/search?part=snippet&q=${keywords}&maxResults=10&type=video&order=viewCount&videoDuration=short&publishedAfter=2022-09-27T00:00:00Z`).getContentText());
const fSearchResults = searchResults.items.filter(function (sr) { return sr.id.kind === "youtube#video" });
return fSearchResults.map(function (sr) { return [keywords, sr.id.videoId, `https://www.youtube.com/watch?v=${sr.id.videoId}`, sr.snippet.title, sr.snippet.publishedAt, sr.snippet.channelTitle, sr.snippet.channelId, `https://www.youtube.com/channel/${sr.snippet.channelId}`, sr.snippet.thumbnails.high.url] });
});
// 3. Retrieve viewCounts and subscriberCounts.
const { videoIds, channelIds } = modifyResults.reduce((o, r) => {
o.videoIds.push(r[1]);
o.channelIds.push(r[6]);
return o;
}, { videoIds: [], channelIds: [] });
const limit = 50;
const { viewCounts, subscriberCounts } = [...Array(Math.ceil(videoIds.length / limit))].reduce((obj, _) => {
const vIds = videoIds.splice(0, limit);
const cIds = channelIds.splice(0, limit);
const res1 = YouTube.Videos.list(["statistics"], { id: vIds, maxResults: limit }).items.map(({ statistics: { viewCount } }) => viewCount);
const obj2 = YouTube.Channels.list(["statistics"], { id: cIds, maxResults: limit }).items.reduce((o, { id, statistics: { subscriberCount } }) => (o[id] = subscriberCount, o), {});
const res2 = cIds.map(e => obj2[e] || null);
obj.viewCounts = [...obj.viewCounts, ...res1];
obj.subscriberCounts = [...obj.subscriberCounts, ...res2];
return obj;
}, { viewCounts: [], subscriberCounts: [] });
const ar = [viewCounts, subscriberCounts];
const rr = ar[0].map((_, c) => ar.map(r => r[c]));
// 4. Merge data.
const res = modifyResults.map((r, i) => [...r, ...rr[i]]);
// 5. Put values on Spreadsheet.
sheet.getRange(2, 2, res.length, res[0].length).setValues(res);
}
Hourly Trigger youTubeSearchResults
function hourlytrigger() {
if(ScriptApp.getProjectTriggers().filter(t => t.getHandlerFunction() == "youTubeSearchResults").length==0) {
ScriptApp.newTrigger("youTubeSearchResults").timeBased().everyHours(1).create();
}
}
To append data:
sheet.getRange(sheet.getLastRow() + 1, 2, res.length, res[0].length).setValues(res);

Result won't update VAR

I am trying to run a query, inside AXIOS which gets data from a 3rd party URL. Then uses some of that data to search our mongoDB database.
However it seems it won't update var total = 0
While the query below does function correctly, the return result won't allow me to set that it to the query.
Promise.all(arr.forEach( async (id,index) => {
//(CODE REMOVED JUST TO GET THIS FUNCTION TO WORK)
const search = await geoLocation.find({
'location': {
'$geoWithin': {
'$box': [
[-35.2418503, -13.5076852], [112.8656697, 129.0020486]
]
}
}}).toArray();
total = search.length;
}));
See the full code below
var array = [];
var pointarray = []
var total = 0;
areas.forEach((id,index) => {
if(id.type == "Point"){
pointarray[index] = "N"+id.id;
}else{
array[index] = "R"+id.id;
}
});
var arraySearch = "https://nominatim.openstreetmap.org/lookup?osm_ids="+array.toString()+"&polygon_geojson=1&bbox=1&format=json";
var pointSearch = "https://nominatim.openstreetmap.org/lookup?osm_ids="+pointarray.toString()+"&polygon_geojson=1&bbox=0&format=json"
const requestOne = axios.get(arraySearch);
const requestTwo = axios.get(pointSearch);
axios.all([requestOne, requestTwo])
.then(axios.spread((...responses) => {
const responseOne = responses[0]
const responseTwo = responses[1]
/*
process the responses and return in an array accordingly.
*/
return [
responseOne.data,
responseTwo.data,
];
}))
.then(arr => {
Promise.all(arr.forEach( async (id,index) => {
//const middleIndex = id[index].boundingbox.length / 2;
//const firstHalf = id[index].boundingbox.splice(0, middleIndex);
//const secondHalf = id[index].boundingbox.splice(-middleIndex);
//res.send(secondHalf[0]);
const query = [{
$match: {
location: {
$geoWithin: {$box:[[Number(firstHalf[0]),Number(firstHalf[1])],[Number(secondHalf[0]),Number(secondHalf[1])]]
}
}
}
},{
$count: 'id'
}]
const search = await geoLocation.find({
'location': {
'$geoWithin': {
'$box': [
[-35.2418503, -13.5076852], [112.8656697, 129.0020486]
]
}
}}).toArray();
total = search.length;
// total = search.length;
// const search = geoLocation.aggregate(query).toArray.length;
}));
})
.catch(errors => {
console.log("ERRORS", errors);
})
.then(function () {
res.send(total);
});

Setting Array in ReactJS w/ Hooks

I currently have an array of FooBar objects
interface FooBar {
foo: string,
bar: string,
correct: string,
other: string[]
}
const [arrOfObj, setArrOfObj] = useState<FooBar[]>([
{ "foo": "foolicious ", "bar": "barlicious", "correct": "foobarlicious", "other": ["oof", "f00", "rab", "r#b"]},
]);
const [shuffledArrOfObj, setShuffledArrOfObj] = useState<FooBar[]>([
{ "foo": "", "bar": "", "correct": "", "other": [""]},
]);
However I want to randomly shuffle the "other" array in each object so I have a shuffle function:
useEffect(() => {
(async () => {
const act = await shuffleObjs();
setShuffledArrOfObj([...act]);
})();
}, [arrOfObj]);
const shuffleObjs = () => {
let holdArr = [...arrOfObj];
for (let i: number = 0; i < holdArr.length; i++) {
holdArr[i].other = await handleShuffle(holdArr[i].other);
}
}
const handleShuffle = async (array: string[]) => {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
However, if I console.log(holdArr) at the end of the "shuffleObjs" function, the array of objects is totally different than the array of objects stored in the shuffledArryObj state.
Am I setting the array state the wrong way, or is there something I am missing?
EDIT: Typo wasn't the problem, it's still not working correctly. I also tried adding arrOfObj to the dep array.
You're missing two things:
useEffect(() => {
(async () => {
const act = await shuffleObjs();
setShuffledArrOfObj([...act]);
})();
}, [arrOfObj]); //<-- Add arrOfObj to dependency Array
const shuffleObjs = () => {
let holdArr = [...arrOfObj];
for (let i: number = 0; i < holdArr.length; i++) {
holdArr[i].other = await handleShuffle(hold[i].other); //<-- change hold[i] to holdArr[i]
}
}

How can I push array-data one scope higher

I need the data from time_array outside of the first loop. When I console.log(time_array) inside the first loop I get the following results:
MongoClient.connect(CONNECTION_URL, { useNewUrlParser: true }, function (err, db) {
if (err) throw err;
var db = db.db("coinlib");
const userid = '5de2c1be7224c00e6723b7e3';
const time_array = [];
db.collection("users").findOne({ _id: ObjectID(userid) }, function (err, portfolio) {
if (err) throw err;
const portfolio_length = portfolio.portfolio.length;
for (let i = 0; i < portfolio_length; i++) {
db.collection("coin-data-24h").findOne({ ticker: portfolio.portfolio[i].ticker }, function (err, coin_data_24h) {
if (err) throw err;
for (let ii = 0; ii < portfolio.portfolio[i].node_count; ii++) {
// Filter data between startDate and endDate
const startDate = new Date(portfolio.portfolio[i].nodes[ii].online_since);
const endDate = new Date();
const dataset = coin_data_24h.dataset;
let result = dataset.filter(item => new Date(item.timestamp) >= startDate && new Date(item.timestamp) <= endDate)
// Create array and fill it with 0
const array_with_zeros = Array.from(Array(3), () => 0)
// Return 3 results only
const array_with_data = result.slice(0, 3);
// How many results are in there
const length_array_with_data = array_with_data.length;
const start_index = 3 - length_array_with_data;
for (let i = 0; i < length_array_with_data; i++) {
array_with_zeros[start_index + i] = array_with_data[i].usd_price;
}
time_array.push(array_with_zeros);
} // for end
console.log(time_array);
}) // db end
} // for end
console.log(time_array);
}); // db end
}); // Mongo end
Result:
[ [ 5.619693750948361, 12.291785200236262, 57.45995830212961 ],
[ 19.577872231080086, 36.00637519615492, 24.425419908972522 ],
[ 19.577872231080086, 36.00637519615492, 24.425419908972522 ] ]
[ [ 5.619693750948361, 12.291785200236262, 57.45995830212961 ],
[ 19.577872231080086, 36.00637519615492, 24.425419908972522 ],
[ 19.577872231080086, 36.00637519615492, 24.425419908972522 ],
[ 0.7144408839408483, 2.256984583694044, 0.2710203249491058 ] ]
When I console.log(time_array) outside of the first loop, I get an empty array.
Please tell me why? I defined time_array outside of the loops, so it should work. Thank you so much.

React : Need a faster way to filter data and setState

I need to make a menu list for a restaurant app, and the menu data is categorized in American, Chinese, Indian, Italian. I need to loop over all these to render it somehow in the scrollspy type menu.
For that I have configured the backend to send in ALL the ITEMS at once and need to filter and sort it as per the category on the react side.
DATA STRUCTURE :
{
_id: 5eef61450bd95e1f5c8f372f
name: "Burger"
category: "American"
price: "100"
isVeg: false
__v: 0
}
The way i am doing is seems too slow and I believe there is GOT TO BE A FASTER/EFFECIENT WAY. Please suggest, because my way makes me want to puke.
const CheckForms = () => {
const [american, setAmerican] = useState([]);
const [italian, setItalian] = useState([]);
const [indian, setIndian] = useState([]);
const [chinese, setChinese] = useState([]);
const fetchList = async () => {
try {
const res = await axios.get(`http://localhost:5000/api/items`);
const list = res.data.response;
let ch = [];
let ind = [];
let am = [];
let it = [];
list.forEach(function(each){
if (each.category === "Chinese") ch.push(each)
else if (each.category === "Indian") ind.push(each)
else if (each.category === "American") am.push(each)
else if (each.category === "Italian") it.push(each)
else console.log('undefined category');
});
setAmerican(am);
setIndian(ind);
setChinese(ch);
setItalian(it);
} catch (err) {
console.log(err.response);
};
};
useEffect(()=> {
fetchList();
}, []);
let render;
if (indian.length > 0 && american.length > 0 && chinese.length > 0 && italian.length > 0) {
render = (
/*********************************
* AND FURTHER RENDERING LOGIC :(
********************************/
);
};
You could try reduce:
const list = [
{ category: 'Chinese', name: 'one-1' },
{ category: 'Chinese', name: 'one-2' },
{ category: 'Indian', name: 'two' },
];
const groups = list.reduce(
(result, item) =>
result.set(
item.category,
(result.get(item.category) || []).concat(item)
),
new Map()
);
console.log('Chinese',groups.get('Chinese'));
console.log('Indian',groups.get('Indian'));

Categories

Resources