generating random numbers that don't repeat - flutter

I have a list of strings that when button is pressed, uses the random widget to randomly select one to be saved as a string for use later.
void Randomiser() {
savedString = listOfStrings[Random().nextInt(9)];
}
the above code works but it often randomises the same number multiple times in a row, which i don't want.
I saw someone had posted this code as a fix:
Set<int> setOfInts = Set();
setOfInts.add(Random().nextInt(max));
which works but I can't get it to then save to the string.
thanks so much

you can use your method and store the last returned random number to be sure that you don't get it again :
import 'dart:math';
void main() {
var lastRandom = 1;
final listOfStrings = ['first','second','third'];
String Randomiser(lastRandom) {
var newRandom = lastRandom;
while(newRandom == lastRandom){
newRandom = Random().nextInt(3);
}
lastRandom = newRandom;
return listOfStrings[newRandom];
}
for( var i = 0 ; i < 20; i++ ) {
print(Randomiser(lastRandom));
}
}

Related

Flutter List after storing all data in a for-loop, when out of loop replace all stored records with the last record. Why's that?

I want to pass data from json to a list. I load the list with data into a for-loop, and it works as expected, loading 6 records into my list. But when I verify when for-loop is done, my list keep only the last data in all 6 records. Why's that?
This is my code:
class LoadData {
loadSalesData() async {
String optiune = 'gen';
String numeServer = Global.server;
String tabel = Global.tabel;
SalesData sd = SalesData("", 0.00);
List<SalesData> sData = [];
Loader kk = Loader();
kk
.searchOnServer(tabel: tabel, numeServer: numeServer, optiune: optiune, dataInceput: "2022-06-30", dataSfarsit: "2022-07-23")
.then((rezultat) async {
try {
rezultat = "[" + rezultat + "]";
var _json = jsonDecode(rezultat);
Global.dataChart = [];
for (int i = 0; i < _json.length; i++) {
// window.alert(_json[i]['partener'] + " Lenght:" + _json.length.toString());
sd.partener = _json[i]['partener'];
sd.sales = double.parse(_json[i]['Sales']);
Global.dataChart.add(sd);
//This show the list correctly with all data from server
window.alert("Into for-loop $i:" + Global.dataChart[i].partener);
}
//This shows only the last record no matter the List index (i.e. [0],[1]...etc
window.alert("Outside for-loop: " + Global.dataChart[0].partener);
//This shows the same value as the previous
window.alert("Outside for-loop: " + Global.dataChart[1].partener);
} catch (e) {
print(e);
}
});
}
}
//Global.dataChart is defined in a separate class as static List<SalesData> dataChart = [];
//and class SalesData is..
class SalesData {
String partener;
double sales;
SalesData(this.partener, this.sales);
}
It is because you're editing the same instance of SalesData sd and dart uses call by reference on Objects of non-primitive types.
Put SalesData sd = SalesData("", 0.00); in the loop instead.
Like so:
for (int i = 0; i < _json.length; i++) {
SalesData sd = SalesData("", 0.00);
// window.alert(_json[i]['partener'] + " Lenght:" + _json.length.toString());
sd.partener = _json[i]['partener'];
sd.sales = double.parse(_json[i]['Sales']);
Global.dataChart.add(sd);
//This show the list correctly with all data from server
window.alert("Into for-loop $i:" + Global.dataChart[i].partener);
}
To easily reproduce and better understand, try this:
void main() {
final x = X("random");
final l = [];
for(int i =0; i < 3; i ++){
x.a = i.toString();
l.add(x);
}
l.forEach((e) => print(e.a));
}
class X{
String a;
X(this.a);
}

Dart split integer and add their values

Suppose I have a variable int a = 12345, I want to split a to [1,2,3,4,5] and add them like [1+2+3+4+5] and in final I want to get a result of a = 15 how can I achieve this?
All u have to do is recursively add every digit individually.
void main() {
int a = 12345;
int sum = 0;
while(a>0){
sum = sum + (a%10);
a = (a/10).floor();
}
print(sum);
//if u want to store in a
a = sum;
}
There are different ways to achieve the same, one of the ways is as:
void main() {
int num = 12345;
int sum = 0;
String numAsString = num.toString();
for (int i = 0; i < numAsString.length; i++) {
sum += int.parse(numAsString[i]);
}
print(sum); // 15
}
You can achieve using the split() as
void main(){
var i=34567;
var iStr=i.toString().split('');
var exp= iStr.join('+');
var sum=iStr.fold(0,(a,b)=>int.parse(a.toString())+int.parse(b));
print(exp);
print(sum);
}
Output:
3+4+5+6+7
25
If you need only the sum of the integer then
void main() {
var i = 34567;
var iStr = i.toString().split('');
var sum = iStr.fold(0, (a, b) => int.parse(a.toString()) + int.parse(b));
print(sum);
}
I would approach it by first converting the integer to a String.
Then mapping each single character into an int and finally simply
reduce the iterator of ints into the sum.
int num = 12345;
print(num
.toString()
.split('')
.map(
(c) =>int.parse(c)
).reduce((a,b) => a+b));

Audioworklet loop

I'm trying to create an audioworklet that loops a single instance of a sound to create a sort of sustain effect. No matter how many sections of the input I loop, I keep hearing a blip type skipping sound. How many calls to the processor is one instance?
To give you an idea, this is what I have so far:
constructor() {
super();
this.sound = [];
this.count = 20;
this.step = [0, 0];
}
process(inputs, outputs, parameters) {
if (inputs && inputs.length) {
for (var i = 0; i < inputs[0].length; i++) {
var input = inputs[0][i];
var output = outputs[0][i];
if (!this.sound[i]) {
this.sound[i] = [];
}
if (this.sound[i].length < this.count) {
this.sound[i].push([]);
for (var j = 0; j < input.length; j++) {
this.sound[i][this.sound[i].length - 1][j] = input[j];
}
} else if (this.sound[i]) {
var s = this.sound[i][this.step[i] % this.sound[i].length];
for (var j = 0; j < s.length; j++) {
output[j] = s[j];
}
this.step[i]++;
}
}
}
return true;
}
So the idea is that I capture the incoming input in an array of N length for each channel(in my case there are 2 channels). Then once that array is full, I cycle through that array to fill the output until the node is disabled.
Thanks for the fiddle. Very helpful.
I didn't look to see what was causing the clicks, but I took your example and modified it very slightly like so:
// #channels 2
// #duration 1.0
// #sampleRate 44100
var bufferSize = 4096;
let ctx = context;
let osc = ctx.createOscillator();
osc.start();
let myPCMProcessingNode = ctx.createScriptProcessor(bufferSize, 2, 2);
let _count = 1;
var sound = [];
var count = _count++;
console.log(count)
var hesitate = 0;
var step = [0, 0];
//Logic to pay attention to
myPCMProcessingNode.onaudioprocess = function(e) {
for(var i = 0; i<2; i++){
var input = e.inputBuffer.getChannelData(i);
var output = e.outputBuffer.getChannelData(i);
if (!sound[i]) {
sound[i] = [];
}
if (sound[i].length < count) {
sound[i].push([]);
for (var j = 0; j < input.length; j++) {
sound[i][sound[i].length - 1][j] = input[j];
}
} else if (sound[i]) {
var s = sound[i][step[i] % sound[i].length];
for (var j = 0; j < s.length; j++) {
output[j] = s[j];
}
step[i]++;
}
}
}
//To hear
osc.connect(myPCMProcessingNode).connect(ctx.destination);
I pasted this in the code window at https://hoch.github.io/canopy. Press the top left button (arrow) to the left of the code window, and you can see the rendered audio. You can see that the output (frequency is 10 instead of 440 to make it easier to see) is discontinuous. This causes the clicks you hear. You can also change the frequency to 100 and find discontinuities in the output.
I hope this is enough to help you figure out what's wrong with your buffering.
An alternative is to create an AudioBufferSourceNode with an AudioBuffer of the basic sample. You can set the AudioBufferSourceNode to loop the whole buffer. This doesn't solve the clicking problem, but it is somewhat simpler.
But this is a general problem of looping any buffer. Unless you arrange the last sample to be close to the first sample, you will hear clicks when you wrap around. You either need to grab chunks where the first and last samples are nearly the same, or modified the chunks so they ramp up at the beginning in some way and ramp down at the end in some way.

Flutter Random Number generator for different quiz sizes

I'm building a language teaching app that provides the user with a quiz for every topic.
I've found a neat solution for the quiz-structure.
But the problem is, that every quiz has a different size and I don't know how to adjust the Random number generator, so that it'll produce only random numbers for the current quiz-size.
I need a self-adjusting RNG, but I have no imagination of how to do this.
Here's my random number generator.
genrandomarray() {
var distinctIds = [];
var rand = new Random();
for (int i = 0;;) {
distinctIds.add(rand.nextInt(10) + 1);
random_array = distinctIds.toSet().toList();
if (random_array.length < 10) {
continue;
} else {
break;
}
}
print(random_array);
}
For example one topic has 12 questions, one 30, and so on.
Random rnd;
int min = 0;
int max = 10;
rnd = new Random();
r = min + rnd.nextInt(max - min);
print("$r is in the range of $min and $max");
If you can pass by parameter the maximum value is a correct way:
genrandomarray(int max_value) {
var distinctIds = [];
var rand = new Random();
rand = rand.nextInt(max_value);
for (int i = 0;i<rand;i++) {
distinctIds.add(rand.nextInt(10) + 1);
random_array = distinctIds.toSet().toList();
if (random_array.length < 10) {
continue;
} else {
break;
}
}
print(random_array);
}

Google Spreadsheet - How to avoid sending email duplicates?

I am having an issue with a script. I used the following script from Google Developers Website in order to do a simple merge mail. See https://developers.google.com/apps-script/articles/mail_merge
I modified a bit the script so to prevent email duplicates. However, even if the script seems to work as it marks 'EMAIL_SENT' in each row every time an email is sent. It does not pay attention if the mail as already been marked and still send the mail.
I believe there is an error at line 16 "var emailSent = rowData[6];"
I would really appreciate if someone could help me. Whoever you are thanks in advance.
Here is the modified script :
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheets()[0];
var dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows() - 1, 7);
var templateSheet = ss.getSheets()[1];
var emailTemplate = templateSheet.getRange("A2").getValue();
var objects = getRowsData(dataSheet, dataRange);
for (var i = 0; i < objects.length; ++i) {
var Resume = DriveApp.getFilesByName('Resume.pdf') var Portfolio = DriveApp.getFilesByName('Portfolio.pdf') var rowData = objects[i];
var emailText = fillInTemplateFromObject(emailTemplate, rowData);
var emailSubject = "Architectural Internship";
var emailSent = rowData[6];
if (emailSent != EMAIL_SENT) {
MailApp.sendEmail(rowData.emailAddress, emailSubject, emailText, {
attachments: [Resume.next(), Portfolio.next()]
});
dataSheet.getRange(2 + i, 7).setValue(EMAIL_SENT);
SpreadsheetApp.flush();
}
}
}
function fillInTemplateFromObject(template, data) {
var email = template;
var templateVars = template.match(/\${\"[^\"]+\"}/g);
for (var i = 0; i < templateVars.length; ++i) {
var variableData = data[normalizeHeader(templateVars[i])];
email = email.replace(templateVars[i], variableData || "");
}
return email;
}
function getRowsData(sheet, range, columnHeadersRowIndex) {
columnHeadersRowIndex = columnHeadersRowIndex || range.getRowIndex() - 1;
var numColumns = range.getEndColumn() - range.getColumn() + 1;
var headersRange = sheet.getRange(columnHeadersRowIndex, range.getColumn(), 1, numColumns);
var headers = headersRange.getValues()[0];
return getObjects(range.getValues(), normalizeHeaders(headers));
}
function getObjects(data, keys) {
var objects = [];
for (var i = 0; i < data.length; ++i) {
var object = {};
var hasData = false;
for (var j = 0; j < data[i].length; ++j) {
var cellData = data[i][j];
if (isCellEmpty(cellData)) {
continue;
}
object[keys[j]] = cellData;
hasData = true;
}
if (hasData) {
objects.push(object);
}
}
return objects;
}
function normalizeHeaders(headers) {
var keys = [];
for (var i = 0; i < headers.length; ++i) {
var key = normalizeHeader(headers[i]);
if (key.length > 0) {
keys.push(key);
}
}
return keys;
}
function normalizeHeader(header) {
var key = "";
var upperCase = false;
for (var i = 0; i < header.length; ++i) {
var letter = header[i];
if (letter == " " && key.length > 0) {
upperCase = true;
continue;
}
if (!isAlnum(letter)) {
continue;
}
if (key.length == 0 && isDigit(letter)) {
continue;
}
if (upperCase) {
upperCase = false;
key += letter.toUpperCase();
} else {
key += letter.toLowerCase();
}
}
return key;
}
// Returns true if the cell where cellData was read from is empty. // Arguments: // - cellData: string function isCellEmpty(cellData) {
return typeof(cellData) == "string" && cellData == "";
}
// Returns true if the character char is alphabetical, false otherwise. function isAlnum(char) { return char >= 'A' && char <= 'Z' || char >= 'a' && char <= 'z' || isDigit(char); }
// Returns true if the character char is a digit, false otherwise. function isDigit(char) { return char >= '0' && char <= '9'; }
Your code is really hard to read and the functions that return 2 or more objects make it even harder...you are using variable names that are also a bit confusing.... but that is probably a personal pov :-)
Anyway, I think I've found the issue: when you write var rowData = objects[i];
This "object" is actually the result of the getRowData function but if you look at this function, you'll see that it returns 2 objects, the first one being itself the result of another function (getObjects) ...
You are checking the value is the 6th element of the array which is actually an object and compare it to a string. The equality will never be true.
I didn't go further in the analyse since I found it really confusing ( as I already said) but at least you have a first element to check .
I would suggest you rewrite this code in a more simple way and use more appropriate variable names to help you while debugging.
I would recommend logging both values before executing to make sure they are the same. I would also guess that the email_sent and EMAIL_SENT are different data types. Can also try forcing the value to string for comparison.
To clarify:
logger.Log(emailSent);
logger.Log(EMAIL_SENT);
if (emailSent.toString() != EMAIL_SENT.toString())
{...
Error is in this line of code -
var dataRange = sheet.getRange(startRow, 1, numRows, 2)
It's considering only 2 columns in the range. Changed 2 to 3 and it worked fine.