Displaying strings in iOS randomly without repeating them
If I understand your requirements correctly:
- You want to persist the randomly generated numbers between View Controller instances and application launches
- you never want to repeat any question
A quick way to achieve this is to use NSUserDefaults
to keep track of the order and value of (pseudo)random numbers from your PRNG. This way, you can instantiate the array of avaiable questions on instantaition by replaying previous dice rolls, removing those questions from the pool alongside in the right order.
This also lets you handle the PRNG as a black box, not caring about seeding and replay.
Also, make sure to remove any chosen questions from the current pool for any dice roll.
Side note: You are not following naming conventions - functions are to be starting lower case, for example.
For your own good and readability, please follow prevalent conventions, at least when sharing your code with others. Better yet, all the time.
Edit:
To be more verbose:
NSUserDefaults
can save small amounts of data for you in an easy way. If you 'just want to remember an array of numbers', it's the go to place.suppose your data is helt in an instance variable like so:
var questions : [Question] = // load the questions - carefully, see below.
you can easily remove the question your PSNG (pseudo-random number generator) selects like so:
let randomNumber = Int(arc4random_uniform(UInt32(questions.count)))
questions.removeAtIndex(randomNumber)Thus the next dice roll (e.g. invocation of your PSNG) is guaranteed not to select the question already asked because it is no longer in the pool of avaiable questions it selects from.
This approach does need you to save all your random numbers in the right order to 'replay' what has happened before when you are instantiating a new instance (for example, because the app has been reopened). That's where
NSUserDefaults
'setObject:forKey:
andobjectForKey:
come into play when loading the questions initially and 'remembering' every new dice roll.
I hope, this covers what you might didn't understand before.
Randomly choosing an item from a Swift array without repeating
Create an array of indexes. Remove one of the indexes from the array and then use that to fetch a color.
Something like this:
var colorArray = [
(UIColor.redColor(), "red"),
(UIColor.greenColor(), "green"),
(UIColor.blueColor(), "blue"),
(UIColor.yellowColor(), "yellow"),
(UIColor.orangeColor(), "orange"),
(UIColor.lightGrayColor(), "grey")]
var indexes = [Int]();
func randomItem() -> UIColor
{
if indexes.count == 0
{
print("Filling indexes array")
indexes = Array(0..< colorArray.count)
}
let randomIndex = Int(arc4random_uniform(UInt32(indexes.count)))
let anIndex = indexes.removeAtIndex(randomIndex)
return colorArray[anIndex].0;
}
The code above creates an array indexes
. The function randomItem
looks to see if indexes
is empty. if it is, it populates it with index values ranging from 0 to colorArray.count - 1
.
It then picks a random index in the indexes
array, removes the value at that index in the indexes
array, and uses it to fetch and return an object from your colorArray
. (It doesn't remove objects from the colorArray
. It uses indirection, and removes objects from the indexesArray, which initially contains an index value for each entry in your colorArray
.
The one flaw in the above is that after you fetch the last item from indexArray, you populate it with a full set of indexes, and it's possible that the next color you get from the newly repopulated array will be the same as the last one you got.
It's possible to add extra logic to prevent this.
Display String From Array Randomly, only once, and change each day
You could update your plist to either remove the quote or set a flag as used then exclude those from being selected.
As far as when to mark one as used. I'm not sure everyday at midnight works with your model If its truly random then marking them as used at midnight doesn't make much sense since they may not open the app every day and would miss random quotes. Where as if it were ordered there would be a quote a day.
EDIT FROM OP:
In the AppDelegate didFinishLaunch I added this code:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (! [defaults boolForKey:@"notFirstRun"]) {
[defaults setBool:YES forKey:@"notFirstRun"];
[defaults setInteger:0 forKey:@"verseKey"];
[defaults synchronize];
}
NSTimeInterval date = [defaults doubleForKey:@"startTimeInterval"];
NSTimeInterval dateNow = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval difference = dateNow - date;
difference = difference / 84000;
if(difference >= 0 && difference <= 1) {
}
if(difference >= 1 ) {
NSLog(@"ITSMORE");
NSInteger savedIndex = [[NSUserDefaults standardUserDefaults] integerForKey:@"verseKey"];
savedIndex +=1;
if (savedIndex == 200) {
[defaults setInteger:0 forKey:@"verseKey"];
dateNow = [NSDate timeIntervalSinceReferenceDate];
[defaults setDouble:dateNow forKey:@"startTimeInterval"];
[defaults synchronize];
}
else {
[defaults setInteger:savedIndex forKey:@"verseKey"];
dateNow = [NSDate timeIntervalSinceReferenceDate];
[defaults setDouble:dateNow forKey:@"startTimeInterval"];
[defaults synchronize];
}
}
I believe that this code should set the value of 0 for verseKey on firstRun and synchronize it with NSUserDefaults. Then, each time it is launched, it will see if more than 24 hours have passed. If it has, then it will add 1 to the key of verseKey until it hits 200 (I have a total of 200 quotes). Once 200 has been hit, it will reset it to 0. Then I set the TextView to objectAtIndex:key for verses, so that it will change. Sound about right?
Random number without repeat in swiftUI
This approach uses an extra observable class. It copies the 6 numbers into a temporary array. On tap one random number is removed from the array (this number is being displayed) so each number is only used once. If the array is empty the cycle starts over.
class Random : ObservableObject {
var array = [Int]()
@Published var randomNumber = 0
func next() {
if array.isEmpty { array = [1,2,3,4,5,6] }
let index = Int.random(in: 0..<array.count)
randomNumber = array.remove(at: index)
}
}
struct RanNum: View {
@StateObject private var random = Random()
var body: some View {
VStack{
Text(random.randomNumber == 0 ? "" : "\(random.randomNumber)")
.padding()
.multilineTextAlignment(.center)
.background(Color.white.opacity(0.5))
.cornerRadius(10)
.frame(width: 390, alignment: .center)
Button(action: {
random.next()
}) {
Image(systemName: "arrow.counterclockwise.circle.fill")
.foregroundColor(.black)
.font(.system(size: 30))
.padding()
}
}
}
}
Unity C# Cycling some texts without repeating them
You can remove the switch
statement and store each message in a list.
var tips = new List<string>();
tips.Add("The clouds are white");
...
Then you can randomize the elements in the list (more on that here) and show tips one by one. All you need is to keep track of the index. Example:
// This needs to be a field.
int index = 0;
void ShowTip()
{
// TODO: make sure index is not equal or greater than tips.Count
tip = tips[index];
index++;
// Display the tip
}
Non repeating random numbers in iOS?
NSMutableArray *storeArray = [[NSMutableArray alloc] init];
BOOL record = NO;
int x;
for (int i=0; [storeArray count] < 10; i++) //Loop for generate different random values
{
x = arc4random() % 10;//generating random number
if(i==0)//for first time
{
[storeArray addObject:[NSNumber numberWithInt:x]];
}
else
{
for (int j=0; j<= [storeArray count]-1; j++)
{
if (x ==[[storeArray objectAtIndex:j] intValue])
record = YES;
}
if (record == YES)
{
record = NO;
}
else
{
[storeArray addObject:[NSNumber numberWithInt:x]];
}
}
}
NSLog(@" Non Repeated Random Numbers : %@",storeArray);
can u try this code may be it's use full to you
Randomly select 5 elements from an array list without repeating an element
You can do it like this:
let array1 = ["salmon", "turkey", "salad", "curry", "sushi", "pizza", "curry", "sushi", "pizza"]
var resultSet = Set<String>()
while resultSet.count < 5 {
let randomIndex = Int(arc4random_uniform(UInt32(array1.count)))
resultSet.insert(array1[randomIndex])
}
let resultArray = Array(resultSet)
print(resultArray)
A set
can contain unique elements only, so it can't have the same element more than once.
I created an empty set
, then as long as the array contains less than 5 elements (the number you chose), I iterated and added a random element to the set
.
In the last step, we need to convert the set to an array to get the array that you want.
How to generate non repeating random numbers in ios?
Use arc4random()
Example:
- (NSData *)randomBytes:(size_t)count
{
NSMutableData *data = [NSMutableData dataWithLength:count];
SecRandomCopyBytes( kSecRandomDefault,
data.length,
data.mutableBytes);
return data;
}
It turns out that getting a random number in a range is not as simple as using mod.
- (u_int32_t)randomInRangeLo:(u_int32_t)loBound toHi:(u_int32_t)hiBound
{
u_int32_t random;
int32_t range = hiBound - loBound + 1;
u_int32_t limit = UINT32_MAX - (UINT32_MAX % range);
do {
random = arc4random();
} while (random > limit);
return loBound + (random % range);
}
Related Topics
Ruby: Loaderror - Library Not Found for Class Digest::Sha1 -- Digest/Sha1
Pausing Timer When App Is in Background State Swift
How to Update Particular Value of Child in Firebase Db
Swift - Update/Refresh Label That Displays Time
Storing a Variable When the App Is First Installed
How to Catch Accessibility Focus Changed
Passing Data Between Interface Controllers in Watchkit
How to Send Request from iOS (Swift) to Dialogflow V2 API Without Cloud Functions
Landscape Orientation for Collection View in Swift
How to Open Amazon App from Within My App
Swift Language Multicast Delegate
Nsfilemanager Moveitem Throws Error Code=513
Admob Interstitial Alway Returns False
Swift 2 - Separating an Array into a Dictionary with Keys from a to Z
Post Parameter to Sever Using Dictionary Swift
Uicollectionviewcontroller Error in Swift 3.0: Must Be Initialized with a Non-Nil Layout Parameter