I have 2 strings in an array. I want there to be a 10% chance of one and 90% chance to select the other. Right now I am using:
Random random = new Random();
int x = random.nextInt(100 - 1) + 1;
if (x < 10) {
string = stringArray(0);
} else {
string = stringArray(1);
}
Is this the best way of accomplishing this or is there a better method?
I know it's typically a bad idea to submit a stack overflow response without submitting code, but I really challenge this question of " the best way." People ask this all the time and, while there are established design patterns in software worth knowing, this question almost always can be answered by "it depends."
For example, your pattern looks fine (I might add some comments). You might get a minuscule performance increase by using 1 - 10 instead of 1 - 100, but the things you need to ask yourself are as follows :
If I get hit by a bus, is the person who is going to be working on the application going to know what I was trying to do?
If it isn't intuitive, I should write a comment. Then I should ask myself, "Can I change this code so that a comment isn't necessary?"
Is there an existing library that solves this problem? If so, is it FOSS approved (if applicable) / can I use it?
What is the size of this codebase eventually going to be? Am I making a full program with microservices, a DAO, DTO, Controller, View, and different layers for validation?
Is there an existing convention to solve my problem (either at my company or in general), or is it unique enough that I can take my own spin on it?
Does this follow the DRY principle?
I'm in (apparently) a very small camp on stack overflow that doesn't always believe in universal "bests" for solving code problems. Just remember, programming is only as hard as the problem you're trying to solve.
EDIT
Since people asked, I'd do it like this:
/*
* #author DaveCat
* #version 1.0
* #since 2019-03-9
* Convenience method that calculates 90% odds of A and 10% odds of B.
*
*/
public static String[] calculatesNinetyPercent()
{
Random random = new Random();
int x = random.nextInt(10 - 1 ) + 1
//Option A
if(x <= 9) {
return stringArray(0);
}
else
{
//Option B
return stringArray(1);
}
}
As an aside, one of the common mistakes junior devs make in enterprise level development is excessive comments.This has a javadoc, which is probably overkill, but I'm assuming this is a convenience method you're using in a greater program.
Edit (again)
You guys keep confusing me. This is how you randomly generate between 2 given numbers in Java
One alternative is to use a random float value between 0..1 and comparing it to the probability of the event. If the random value is less than the probability, then the event occurs.
In this specific example, set x to a random float and compare it to 0.1
I like this method because it can be used for probabilities other than percent integers.
Related
This is a design pattern I see coming up a lot in game design and game programming. I've written the code in Java, but this is more about algorithm design.
I want my program to go down various path based on a random chance, and I want to be able to specify the chance for each path.
For example, I want the program to randomly choose whether or not someone gets their last name from their father or mother, or neither, with different weightings for each of those paths.
//Last Name
int lastNameProc = rand.nextInt(100);
if(lastNameProc < 6){ //Orphan or Disowned by father
if(lastNameProc < 2) { //Orphan
lName = "Smith";
} else { //Disowned
lName = mother.lastName;
}
} else { //Not Orphan or Disowned
lName = father.lastName;
}
This can also be done with inequalities instead of nested if statements. The problem with doing it that way is that it's not obvious from the else-if clauses what percentage chance an event has of occurring.
Is there a common or better way of doing this?
Another way to phrase this question:
If I had a sword in an RPG where on a hit the sword applies one of 4 effects, fire, cold, radiant or necrotic damage, with the probability of each being 0.1, 0.2, 0.2 and 0.5. How would I program this without using nested if statements or inequality based if-else statements. I believe this is called an on-hit proc in game design terms.
My question is quite similar to "Generate A Weighted Random Number" however I am unable to translate the code in the answer because I can't figure out which types to use. It would be nice to see a strongly typed example.
Finally, I'm not sure if these are the correct names for this pattern and I'll edit the title to include the correct words.
I have an array list with some names inside it (first and last names). What I have to do is go through each "first name" and see how many times a character (which the user specifies) shows up at the end of every first name in the array list, and then print out the number of times that character showed up.
public int countFirstName(char c) {
int i = 0;
for (Name n : list) {
if (n.getFirstName().length() - 1 == c) {
i++;
}
}
return i;
}
That is the code I have. The problem is that the counter (i) doesn't add 1 even if there is a character that matches the end of the first name.
You're comparing the index of last character in the string to the required character, instead of the last character itself, which you can access with charAt:
String firstName = n.getFirstName()
if (firstName.charAt(firstName.length() - 1) == c) {
i++;
}
When you're setting out learning to code, there is a great value in using pencil and paper, or describing your algorithm ahead of time, in the language you think in. Most people that learn a foreign language start out by assembling a sentence in their native language, translating it to foreign, then speaking the foreign. Few, if any, learners of a foreign language are able to think in it natively
Coding is no different; all your life you've been speaking English and thinking in it. Now you're aiming to learn a different pattern of thinking, syntax, key words. This task will go a lot easier if you:
work out in high level natural language what you want to do first
write down the steps in clear and simple language, like a recipe
don't try to do too much at once
Had I been a tutor marking your program, id have been looking for something like this:
//method to count the number of list entries ending with a particular character
public int countFirstNamesEndingWith(char lookFor) {
//declare a variable to hold the count
int cnt = 0;
//iterate the list
for (Name n : list) {
//get the first name
String fn = n.getFirstName();
//get the last char of it
char lc = fn.charAt(fn.length() - 1);
//compare
if (lc == lookFor) {
cnt++;
}
}
return cnt;
}
Taking the bullet points in turn:
The comments serve as a high level description of what must be done. We write them aLL first, before even writing a single line of code. My course penalised uncommented code, and writing them first was a handy way of getting the requirement out of the way (they're a chore, right? Not always, but..) but also it is really easy to write a logic algorithm in high level language, then translate the steps into the language learning. I definitely think if you'd taken this approach you wouldn't have made the error you did, as it would have been clear that the code you wrote didn't implement the algorithm you'd have described earlier
Don't try to do too much in one line. Yes, I'm sure plenty of coders think it looks cool, or trick, or shows off what impressive coding smarts they have to pack a good 10 line algorithm into a single line of code that uses some obscure language features but one day it's highly likely that someone else is going to have to come along to maintain that code, improve it or change part of what it does - at that moment it's no longer cool, and it was never really a smart thing to do
Aominee, in their comment, actually gives us something like an example of this:
return (int)list.stream().filter(e -> e.charAt.length()-1)==c).count();
It's a one line implementation of a solution to your problem. Cool huh? Well, it has a bug* (for a start) but it's not the main thrust of my argument. At a more basic level: have you got any idea what it's doing? can you look at it and in 2 seconds tell me how it works?
It's quite an advanced language feature, it's trick for sure, but it might be a very poor solution because it's hard to understand, hard to maintain as a result, and does a lot while looking like a little- it only really makes sense if you're well versed in the language. This one line bundles up a facility that loops over your list, a feature that effectively has a tiny sub method that is called for every item in the list, and whose job is to calculate if the name ends with the sought char
It p's a brilliant feature, a cute example and it surely has its place in production java, but it's place is probably not here, in your learning exercise
Similarly, I'd go as far to say that this line of yours:
if (n.getFirstName().length() - 1 == c) {
Is approaching "doing too much" - I say this because it's where your logic broke down; you didn't write enough code to effectively implement the algorithm. You'd actually have to write even more code to implement this way:
if (n.getFirstName().charAt(n.getFirstName().length() - 1) == c) {
This is a right eyeful to load into your brain and understand. The accepted answer broke it down a bit by first getting the name into a temporary variable. That's a sensible optimisation. I broke it out another step by getting the last char into a temp variable. In a production system I probably wouldn't go that far, but this is your learning phase - try to minimise the number of operations each of your lines does. It will aid your understanding of your own code a great deal
If you do ever get a penchant for writing as much code as possible in as few chars, look at some code golf games here on the stack exchange network; the game is to abuse as many language features as possible to make really short, trick code.. pretty much every winner stands as a testament to condense that should never, ever be put into a production system maintained by normal coders who value their sanity
*the bug is it doesn't get the first name out of the Name object
This question already has answers here:
Is finding the equivalence of two functions undecidable?
(9 answers)
Closed 6 years ago.
Is there a way to compare if two methods are equivalent by function (i.e. they do the same thing) rather than equivalent by value (i.e. all of the code in the method is the same) ?
For example these two methods are coded differently, but perform the same function.
public int doIt(int a, int b) {
a = a + 1;
b = b + 1;
return a + b;
}
public int doIt2(int z, int x) {
int total = z + x + 2;
return total;
}
I was looking for a way to do this in Eclipse, but am interested if this is even possible beyond a trivial method.
The only way to be 100% is to mathematically prove it
There are ways:
1- Theorem proving
2- Model Checking
and etc
Although these approaches can be very hard, sometime it might take days to prove it even for trivial programs and even days to produce the adequate abstraction level.
There are some heuristic approaches but obviously they are not 100% accurate (heuristic)
A simple heuristic approach would be to try both methods for 1000 inputs and see if the results are the same
EDIT:
here is a list of Model Checker I found on Wikipedia. I haven't used any of them, they may not be exactly what you are looking for.
https://en.wikipedia.org/wiki/List_of_model_checking_tools
Ignoring side effects, 2 functions will be functionally equivalent if for the same input, they produce the same output.
This will only work for pure code though. There's no way I know of to monitor for side effects in general since the side effects a function carries out could be anything.
Note, there wouldn't be a way to completely verify this without testing every possible input. If the input is just a limited Enum, that might be easy. If it's 2 integers though for example, the total number of combinations would be huge.
In general, the purpose of refactoring is to have a function behave the same before and after it is refactored. Developers generally do this by creating extensive unit tests, testing both normal, edge, and exception cases.
In the OP's two functions to be compared, doIt and doIt2, they might usually return the same answer, given any integer inputs a and b. Unit testing would demonstrate this.
But what if a or b were the largest integer that Java could store, MAX_VALUE?
What if there were a side effect from a=a+1?
In these cases, the two functions may appear similar on the surface, but yield different results.
I have an app that I have made for friends to randomize races for a board game, such that a player gets a randomly selected species every time. I want to include a feature in an update that will allow for a blacklist so that certain races cannot be chosen. What would be the best way to go about this? I'll take any and all advice. Much thanks in advance.
Of note: The array consists of strings of names, and I'd like for this to be persistent for as long as they have the app installed or until they change it.
Edit: Apologies for my lack of clarity. I know generally how I need to do it, but what about saving the settings from the settings menu so that upon closing and reopening, blacklisted races are persistent? Even when the app is closed, upon reopening I'd like for the settings to stay the same. That way next time they play the game (weeks later), assuming their tastes haven't changed, they can go to clicking without blacklisting again.
Without any code, it's hard to say for sure how to go about this, because I don't know how you're implementing the rest of the app.
One way I can think of doing this is if you associate an integer with each race, e.g. by using constants:
public static final GIRAFFE = 1;
public static final GOOSE = 2;
Then you could generate random integers to randomly pick each race. If you created a method for the random integer generation, you could then pass certain numbers that would be excluded. You could keep generating a random integer while the integer generated was one of the excluded numbers.
E.g. (Since it's Android I'll code in Java)
// assume min = smallest integer assigned to an animal,
// and max = largest integer assigned to an animal
public static int randomNumber(int ... exclude)
{
int random = min + (int)(Math.random() * ((max - min) + 1));
for (int i = 0; i < exclude.length; i++)
{
if (exclude[i] == random)
random = Min + (int)(Math.random() * ((Max - Min) + 1));
}
return random;
}
I'm a little new to StackOverflow, so let me know if this helps.
What you need to do is persist data. You can use two solutions:
1) The SharedPreferences framework for saving key-value pairs without any effort. See here to see how to save a list Store a List or Set in SharedPreferences
2) use SQL database. (custom solution)
In case 1 you would persist the blacklisted strings and in case 2 you would be best to create a table with all strings and have a boolean as to whether its blacklisted or not.
I recommend the shared preferences one since it should take you 5 min to do whereas, unless you are familiar with databases, the database solution will take you a while to work out.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 4 years ago.
Improve this question
I work on a project where Spaced Repetition is essential, however I am not a specialist on the subject and I am afraid to reinvent the square wheel. My research pointed me two different systems, namely the Leitner system and the SM family of algorithms.
I haven't decided yet which system would best fit into my project. If I was to take a SM orientation, I guess I would try to implement something similar to what Anki uses.
My best option would be to use an existing Java library. It could be quite simple, all I need is to compute the time for the next repetition.
Has anyone heard of such an initiative ?
I haven't looked at Anki's implementation but have you seen this one? quiz-me an SRS in Java.
Basically it goes like this
public static void calcuateInterval(Card card) {
if (card.getEFactor() < 3) {
card.setCount(1);
}
int count = card.getCount();
int interval = 1;
if (count == 2) {
interval = 6;
} else if (count > 2) {
interval = Math.round(card.getInterval() * card.getEFactor());
}
card.setInterval(interval);
}
If you really want Anki's algorithm, look through the source of Anki in Android available in Github. It is GPL though so you might need to buy a license.
I did reinvent the square wheel in my own flashcard app. The algorithm is quite simple: The weight of an item is the product of an age component, a progress component, and an effort component.
Age component
The formula is A(x) = Cn^x, where
x is the time in days since the item was last tested,
C is the value you want when x is zero, and
n is a constant based on how fast you want the value to increase as x increases.
For example, if you want the value to double every five days, n = e^(ln(2/C)/5).
Progress component
The formula is P(x) = Cn^-x, where
x is a number that corresponds to how successful you've been with the item,
C is the value you want when x is zero, and
n is a constant based on how fast you want the value to decay as x increases.
For example, if you want the value to halve every five consecutive successes, n = e^(ln(1/2)/-5).
Effort component
This takes on one of two values:
10 if you found your last recall of the item to be "hard", or
1 otherwise.
The progress is adjusted thus:
New entries start with progress 0.
If you find an answer easy, the item's progress is increased by 1.
If you find an answer hard, the item's progress goes to min(int(previous / 2), previous - 1).
If you get an answer wrong, the item's progress goes to min(-1, previous - 1).
Yes, values can go negative. :)
The app selects the next item to test by making a random selection from all the items, with the probability of selection varying directly with an item's weight.
The specific numbers in the algorithm are tweakable. I've been using my current values for about a year, leading to great success in accumulating and retaining vocabulary for Spanish, German, and Latin.
(Sorry for potato quality of the math expressions. LaTeX isn't allowed here.)
Anki uses the SM2 algorithm. However, SM2 as described by that article has a number of serious flaws. Fortunately, they are simple to fix.
Explaining how to do so would be too lengthy of a subject for this post, so I've written a blog post about it here. There is no need to use an open-source library to do this, as the actual implementation is incredibly simple.
Here is a spaced repetition algorithm that is well documented and easy to understand.
Features
Introduces sub-decks for efficiently learning large decks (Super
useful!)
Intuitive variable names and algorithm parameters. Fully
open-source with human-readable examples.
Easily configurable
parameters to accommodate for different users' memorization
abilities.
Computationally cheap to compute next card. No need to
run a computation on every card in the deck.
https://github.com/Jakobovski/SaneMemo.
Disclaimer: I am the author of SaneMemo.
import random
import datetime
# The number of times needed for the user to get the card correct(EASY) consecutively before removing the card from
# the current sub_deck.
CONSECUTIVE_CORRECT_TO_REMOVE_FROM_SUBDECK_WHEN_KNOWN = 2
CONSECUTIVE_CORRECT_TO_REMOVE_FROM_SUBDECK_WHEN_WILL_FORGET = 3
# The number of cards in the sub-deck
SUBDECK_SIZE = 15
REMINDER_RATE = 1.6
class Deck(object):
def __init__(self):
self.cards = []
# Used to make sure we don't display the same card twice
self.last_card = None
def add_card(self, card):
self.cards.append(card)
def get_next_card(self):
self.cards = sorted(self.cards) # Sorted by next_practice_time
sub_deck = self.cards[0:min(SUBDECK_SIZE, len(self.cards))]
card = random.choice(sub_deck)
# In case card == last card lets select again. We don't want to show the same card two times in a row.
while card == self.last_card:
card = random.choice(sub_deck)
self.last_card = card
return card
class Card(object):
def __init__(self, front, back):
self.front = front
self.back = back
self.next_practice_time = datetime.utc.now()
self.consecutive_correct_answer = 0
self.last_time_easy = datetime.utc.now()
def update(self, performance_str):
""" Updates the card after the user has seen it and answered how difficult it was. The user can provide one of
three options: [I_KNOW, KNOW_BUT_WILL_FORGET, DONT_KNOW].
"""
if performance_str == "KNOW_IT":
self.consecutive_correct_answer += 1
if self.consecutive_correct_answer >= CONSECUTIVE_CORRECT_TO_REMOVE_FROM_SUBDECK_WHEN_KNOWN:
days_since_last_easy = (datetime.utc.now() - self.last_time_easy).days
days_to_next_review = (days_since_last_easy + 2) * REMINDER_RATE
self.next_practice_time = datetime.utc.now() + datetime.time(days=days_to_next_review)
self.last_time_easy = datetime.utc.now()
else:
self.next_practice_time = datetime.utc.now()
elif performance_str == "KNOW_BUT_WILL_FORGET":
self.consecutive_correct_answer += 1
if self.consecutive_correct_answer >= CONSECUTIVE_CORRECT_TO_REMOVE_FROM_SUBDECK_WHEN_WILL_FORGET:
self.next_practice_time = datetime.utc.now() + datetime.time(days=1)
else:
self.next_practice_time = datetime.utc.now()
elif performance_str == "DONT_KNOW":
self.consecutive_correct_answer = 0
self.next_practice_time = datetime.utc.now()
def __cmp__(self, other):
"""Comparator or sorting cards by next_practice_time"""
if hasattr(other, 'next_practice_time'):
return self.number.__cmp__(other.next_practice_time)