Is there a way in Java to create a collection (map) with fixed size and length?
I.e., I would like to initialize it with K constant keys (e.g. strings) but still want to be able to change the values.
Edit:
The test case has a fixed number of objects, each one corresponds to a number (float). Each time a specific event in the application occurs, I would like to multiply all the numbers in the collection, except the number that corresponds to the object that "caused" the event.
The number is not logically an attribiute of the object.
I suggest you first look at Mike's answer to get an idea of how to go about solving this problem, then make some changes to the code he provided so it will work in your situation:
import java.util.HashMap;
public class InstrumentedHashMap<K> extends HashMap<K, Float> {
private static final long serialVersionUID = 1L;
private int MAX;
public InstrumentedHashMap(int capacity) {
super();
MAX = capacity;
}
#Override
public Float put(K key, Float value) {
if (super.size() >= MAX && !super.containsKey(key)) {
return null;
} else {
super.put(key, value);
return value;
}
}
public void event(K trigger, int multiplyAmount, float subtractAmount) {
super.entrySet().stream().forEach(e -> {
if (!e.getKey().equals(trigger))
e.setValue(e.getValue() * multiplyAmount);
else
e.setValue(e.getValue() - subtractAmount);
});
}
}
You can use the InstrumentedHashMap#event method to handle your "specific event", with the multiplyAmount parameter being the value that you want to multiply your floats by.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I'm looking for some tip on how to do a percentage thing for my game I want all flowers in a range of 1-98 and white/black flowers 99-100 to make it more rarerity thanks for the help :)
public enum FlowerSuit {
WHITE_FLOWERS("white", ":white:", "470419377456414720", 1),
YELLOW_FLOWERS("yellow", ":yellow:", "470419561267855360", 1 ),
RED_FLOWERS("red", ":red:", "470419583250202644", 1),
RAINBOW_FLOWERS("rainbow", ":rainbow:", "470419602841665536", 1),
PASTEL_FLOWERS("pastel", ":pastel:", "470419629450199040", 1),
ORANGE_FLOWERS("orange", ":orange:", "470419647900942366", 1),
BLUE_FLOWERS("blue", ":blue:", "470419688753594368", 1),
BLACK_FLOWERS("black", ":black:", "470419706751352842", 1);
private final String displayName;
private final String emoticon;
private int value;
private final String id;
FlowerSuit(String displayName, String emoticon, String id, int value ) {
this.displayName = displayName;
this.emoticon = emoticon;
this.value = value;
this.id = id;
}
public String getDisplayName() {
return displayName;
}
public String getEmoticon() {
return emoticon;
}
public String getId() {
return id;
}
public int getValue() {
// TODO Auto-generated method stub
return value;
}
}
This is how I'd do it, but it can probably be improved, for starters by using Java 8 streams etc.
public enum FlowerSuit {
WHITE_FLOWERS("white", ":white:", "470419377456414720", 1,3),
YELLOW_FLOWERS("yellow", ":yellow:", "470419561267855360", 1,2),
RED_FLOWERS("red", ":red:", "470419583250202644", 1,2),
RAINBOW_FLOWERS("rainbow", ":rainbow:", "470419602841665536", 1,2),
PASTEL_FLOWERS("pastel", ":pastel:", "470419629450199040", 1,2),
ORANGE_FLOWERS("orange", ":orange:", "470419647900942366", 1,2),
BLUE_FLOWERS("blue", ":blue:", "470419688753594368", 1,2),
BLACK_FLOWERS("black", ":black:", "470419706751352842", 1,1);
private static Random random = new Random();
private final String displayName;
private final String emoticon;
private int value;
private final String id;
private final int freq;
private FlowerSuit(String displayName, String emoticon, String id, int value, int freq ) {
this.displayName = displayName;
this.emoticon = emoticon;
this.value = value;
this.id = id;
this.freq = freq;
}
public String getDisplayName() {return displayName;}
public String getEmoticon() {return emoticon;}
public String getId() {return id;}
public int getValue() {return value;}
/**
* Choose a flower
* white has a 3 in 16 (about a 5:1) chance of being picked
* Black has a 1 in 16 chance, everything else 2/16
* #return
*/
public static FlowerSuit pick() {
//first sum all the chances (currently it's 16)
int sum = 0;
for (FlowerSuit f:FlowerSuit.values()) sum+= f.freq;
//now choose a random number
int r = FlowerSuit.random.nextInt(sum) + 1;
//now find out which flower to pick
sum = 0;
for (FlowerSuit f:FlowerSuit.values()) {
sum += f.freq;
if (r<=sum) return f;
}
//code will never get here
return FlowerSuit.WHITE_FLOWERS;
}
public static void main(final String[] args) throws Exception {
//Test it
Map<FlowerSuit,Integer>count = new HashMap<FlowerSuit,Integer>();
for (int a=0;a<1000000;a++) {
FlowerSuit f = FlowerSuit.pick();
Integer i = (count.get(f)!=null)?count.get(f):new Integer(0);
i = new Integer(i+1);
count.put(f,i);
}
int sum = 0;
for (Map.Entry<FlowerSuit,Integer>e:count.entrySet()) sum+=e.getValue();
float f = Float.valueOf(sum);
for (Map.Entry<FlowerSuit,Integer>e:count.entrySet()) {
System.out.println(e.getKey() + " was chosen " + ((e.getValue() / f) * 100f) + "% of the time");
}
}
}
gives
BLUE_FLOWERS was chosen 12.4986% of the time
PASTEL_FLOWERS was chosen 12.4707% of the time
WHITE_FLOWERS was chosen 18.7365% of the time
BLACK_FLOWERS was chosen 6.2632003% of the time
ORANGE_FLOWERS was chosen 12.4986% of the time
RED_FLOWERS was chosen 12.5241995% of the time
YELLOW_FLOWERS was chosen 12.501401% of the time
RAINBOW_FLOWERS was chosen 12.5068% of the time
You can use a TreeMap to map all of the integers from 0 to 99 to a particular FlowerSuit. Take advantage of the floorEntry method to choose a FlowerSuit for each number. It might look something like this.
public class FlowerChooser {
private static final NavigableMap<Integer, FlowerSuit> FLOWER_SUITS;
private static final Random RANDOMS = new Random();
public FlowerChooser() {
FLOWER_SUITS = new TreeMap<>();
FLOWER_SUITS.put(0, FlowerSuit.RED_FLOWERS);
FLOWER_SUITS.put(14, FlowerSuit.ORANGE_FLOWERS);
FLOWER_SUITS.put(28, FlowerSuit.YELLOW_FLOWERS);
FLOWER_SUITS.put(42, FlowerSuit.GREEN_FLOWERS);
FLOWER_SUITS.put(56, FlowerSuit.BLUE_FLOWERS);
FLOWER_SUITS.put(70, FlowerSuit.INDIGO_FLOWERS);
FLOWER_SUITS.put(84, FlowerSuit.VIOLET_FLOWERS);
FLOWER_SUITS.put(98, FlowerSuit.WHITE_FLOWERS);
FLOWER_SUITS.put(99, FlowerSuit.BLACK_FLOWERS);
}
public FlowerSuit randomFlowerSuit() {
int index = RANDOMS.nextInt(100);
return FLOWER_SUITS.floorEntry(index).getValue();
}
}
Create just one object of this class, then whenever you want a FlowerSuit, call the randomFlowerSuit method.
The randomFlowerSuit method picks a random number from 0 to 99, then finds an appropriate entry in the map. The floorEntry method chooses an entry whose key is less than or equal to the chosen number. This means that numbers from 0 to 13 get mapped to red, 14 to 27 get mapped to orange, and so on. The only number that gets mapped to white is 98, and the only number that gets mapped to black is 99.
No matter what solution you implement, you want to include a frequency measure in your enum. As an example, you can do something like this:
public enum FlowerSuit {
WHITE_FLOWERS("white", ":white:", "470419377456414720", 1, 1),
YELLOW_FLOWERS("yellow", ":yellow:", "470419561267855360", 1, 20),
// More declarations here
// Add this variable
private final int frequency;
// Do just as you did before in the constructor, but with the frequency
FlowerSuit(String displayName, String emoticon, String id, int value, int frequency){
this.frequency = frequency;
// More assignments here
}
public int getFrequency(){
return frequency;
}
// More getters here
}
This addition is critical, and no matter what method you use to weight flower selection, you will want this addition to your FlowerSuit enum.
Now, we can explore a few different ways to perform this selection.
Note 1: I use ThreadLocalRandom for random numbers in a range, which is from java.util.concurrent.ThreadLocalRandom.
Note 2: For each of these, make a single instance of FlowerPicker, and use the pickFlower() method to pick the next flower. This avoid running costly setup code over and over.
Method 1: Bag of Flowers
This method is probably the easiest to implement. It entails creating a list of enums where each is represented frequency times, and then selecting a random entry from this list. It is similar to throwing a bunch of flowers in a bag, shaking it, and then reaching your hand in and grabbing the first flower you touch. Here's the implementation:
public class FlowerPicker(){
private ArrayList<FlowerSuit> bag;
public FlowerPicker(){
// Get all possible FlowerSuits
FlowerSuit[] options = FlowerSuit.values();
// You can use an array here or an array list with a defined length if you know the total of the frequencies
bag = new ArrayList<FlowerSuit>();
// Add each flower from options frequency times
for (FlowerSuit flower : options)
for (int i=0; i<flower.getFrequency(); i++)
bag.add(flower);
}
public FlowerBag pickFlower(){
// Now, select a random flower from this list
int randomIndex = ThreadLocalRandom.current().nextInt(0, bag.size());
return bag.get(randomIndex);
}
}
This method has the advantage of being simple enough to understand very easily. However, it can be inefficient if your frequencies are extremely specific (like if you want a rainbow flower to be returned 499,999,999 times out of 1,000,000,000). Let's move on to the next method.
Note 1: You could make this better by reducing the fractions representing the frequency of being chosen, but I'll leave this to you.
Note 2: You could also make this slightly better by storing identification numbers, not FlowerSuit objects in the bag list.
Method 2: Navigable Map
This method is a little bit more difficult. It uses a [NavigableMap][1], which is an implementation of [TreeMap][2]. This method is fairly similar to the Bag of Flowers method, but it is a little bit more efficient. Put simply, it uses the TreeMap to give each FlowerSuit a range of numbers that can be selected to return that FlowerSuit. Here's a full example:
public class FlowerPicker(){
private NavigableMap<Double, FlowerSuit> map;
public FlowerPicker(){
// Get all possible FlowerSuits
FlowerSuit[] options = FlowerSuit.values();
map = new TreeMap<Double, FlowerSuit>();
int runningTotal = 0;
// Add each flower with the proper range
for (FlowerSuit flower : options){
runningTotal += flower.getFrequency();
map.put(runningTotal, flower);
}
}
public FlowerBag pickFlower(){
// Now, select a random number and get the flower with this number in its range
int randomRange = ThreadLocalRandom.current().nextInt(0, bag.size());
return map.higherEntry(randomRange).getValue();
}
}
This is a solid method, and it scales well for very specific frequencies. If you have a bunch of different types of flowers, it will be slightly worse, but this method is still a good option at large scales. There's one more option though.
Method 3: Enumerated Distribution
This method is really nice because you barely have to do anything. However, it uses [EnumeratedDistribution][3] from Apache Commons. Enumerated Distribution requires a list of pairs of objects and weights. Anyway, lets jump into it:
public class FlowerPicker(){
private EnumeratedDistribution distribution;
public FlowerPicker(){
// Get all possible FlowerSuits
FlowerSuit[] options = FlowerSuit.values();
List<Pair<FlowerSuit, Double>> weights = new List<Pair<FlowerSuit, Double>>();
// Add each flower and weight to the list
for (FlowerSuit flower : options){
weights.add(new Pair(flower, flower.getFrequency()));
// Construct the actual distribution
distribution = new EnumeratedDistribution(weights);
}
public FlowerBag pickFlower(){
// Now, sample the distribution
return distribution.sample();
}
}
This is my favorite method, simply because so much of it is done for you. Many problems like this have been solved, so why not use solutions that always exist? However, there is some value to writing the solution yourself.
In conclusion, each of these methods are perfectly fine to use at your scale, but I would recommend the second or third method.
My teacher gave me confusing instructions on this coding assignment. If you guys could help elaborate or give me tips, I'll provide what I have.
First of all the program is where I have to make 2 classes that will work with a big class to produce a shopping list where you can edit how much of each item you want. Have to take the name of an item, how many times its purchased, and how much each one costs.
I finished my first class, I'll post the entire coding and rules for the coding at the bottom of this question.
Okay so here's what I have. I'll go step by step.
Rule 1: A field private Purchase[] as an array of purchases.
Another int field that tracks how many purchases have actually been made
So I made this:
private int Purchase[];
private int purchaseCount;
Rule 2: Negative values do not make sense, so just reset those to zero if provided by user
Okay so in the first program I had to do the same thing, but I'm confused how to do it now.
I implemented the "reset to zero" in the modifiers, but now my teacher is not asking for modifiers. Am I supposed to put them anyway? I know I just have to put an "if blahblahblah < 0, then blahblahblah = 0" thing, but how do I go about that?
Rule 3: Accessor .length() method that returns your int field for how many purchases
public int Purchase(){
return ;
}
I guess this is about all I know for that. I know I have to return something, not sure how to use length though. And I think there's a parameter.
Final Rule 4: Accessor .get(int) for the Purchase array, which needs a parameter that will index the array. So get(0) returns the first element (a Purchase object) of the array.
I think I understand this, but since I don't know how to do the last step, I haven't tried this yet. ".get(int)" what? So an accessor where I perform a .get(int) inside it? I don't know much about accessors, this is why I need this help. The rest of the program seems pretty simple for me, but this initial stuff confuses me. Thanks.
Rules for already completed class:
Three fields, a String for name of the purchase, int for units purchased, and a double for cost per unit.
• Standard accessors and modifier methods for each field.
• Negative values are not allowed, so change those to zero in all cases.
• Constructor to initialize these three fields (String, int, double) in that order.
• Constructor overload, (String, double) assumes the int quantity is zero.
• Default constructor that assumes name is “” and numbers are zero, must call the three argument constructor.
• A getCost method that is simply the number of units purchased times unit price.
• A toString method return a String with the item name followed by the unit price in parentheses
Completed program:
public class Purchase {
private String purchase;
private int unitsPurchased;
private double costPerUnit;
// Accessors
public String purchase() {
return purchase;
}
public int unitsPurchased() {
return unitsPurchased;
}
public double costPerUnit() {
return costPerUnit;
}
// Modifiers
public void setPurchase(String purchase) {
this.purchase = purchase;
}
public void setunitsPurchased(int unitsPurchased) {
if (unitsPurchased < 0) {
unitsPurchased = 0;
}
this.unitsPurchased = unitsPurchased;
}
public void setCostPerUnit(double costPerUnit) {
if (costPerUnit < 0) {
costPerUnit = 0;
}
this.costPerUnit = costPerUnit;
}
//constructors
public Purchase() {
this("", 0, 0);
}
public Purchase(String initialPurchase, double initialCostPerUnit) {
this.purchase = initialPurchase;
this.unitsPurchased = 0;
this.costPerUnit = initialCostPerUnit;
}
public Purchase(String initialPurchase, int initialUnitsPurchased, double initialCostPerUnit) {
this.purchase = initialPurchase;
this.unitsPurchased = initialUnitsPurchased;
this.costPerUnit = initialCostPerUnit;
}
//end of everything I am sure about
//beginning of unsurety
public static double getCost(String purchase, int unitsPurchased, double costPerUnit) {
return unitsPurchased * costPerUnit;
}
public static String toString(String purchase, int unitsPurchased, double costPerUnit){
return purchase + costPerUnit;
}
}
Okay, so first rule 1 the code should look like:
private Purchase[] purchases;
private int purchaseCount;
Remember, in this case since you've already defined Purchase in your other java file, you're using it as a datatype, not as an identifier.
For rule 2, you're going to want that if statement in the access methods for purchaseCount as well as in the constructor.
Rule 3 is extremely vague...but my best guess is your teacher wants you to define a length method for that class, so that when you call say purchases.length() it returns the purchase count.
Again, rule 4 is vague, but my best guess is you need to define a get method for that class that just returns a value from your private purchases array using a given index.
Something like this:
public Purchase get(int index) {
return purchases[index]
}
I hope this helps and good luck!!
What should be my return at the end of my for loop? I'm trying to display the added results of all three parties numDemocrat, numRepulican and numIndepent by
calculating and then printing the number of democrats (party is "D"),
republicans (party is "R"), and independents (party is anything else).
I'm currently looping over the MemberOfCongress ArrayList returned by parseMembersOfCongress and counting up how many of each party type there are.
Also in my loop I need to check which party the current member belongs to and increment the proper variable. After the loop completes I then print the totals.
public void printPartyBreakdownInSenate()
{
CongressDataFetcher.fetchSenateData(congressNum);
}
{
ArrayList<MemberOfCongress> parseMembersOfCongress; String jsonString;
}
{
System.out.println("Number of Members of the Senate of the " + "&congressNum=" + "?chamber=");
}
public String[]
{
int numDemocrats = 0;
int numRepblican = 0;
int numIndepent = 0;
ArrayList<MemberOfCongress> members;
for (MemberOfCongress memberParty : members) {
if (memberParty.getParty() == "D" ) {
numDemocrats++;
}
else if (memberParty.getParty() == "R" ){
numRepblican++;
}
else if (memberParty.getParty() == "null"){
numIndepent++;
}
}
return ???;
}
Firstly i'm 99% positive you cannot return multiple values, unless your return either an array, an array list or a map.
But what you could do as a work around is one of the following.
1). Return a String array of party members.
2). Return a 2D array mapping name to age or something similar.
3). Return a hashmap of the data with a custom class of information mapped to a name.
4). Use getters to get different pieces of the data at time or all at once.
Java (like the majority of programmming languages) allows only a single return value from a method. There are lots of good reasons for this.
If you need to return multiple values then you will need a separate class for which your method can return a reference to an instance.
For example, in your case:
public enum Party {
REPUBLICAN, DEMOCRAT, OTHER;
}
public Map<Party, Integer> senatorsByParty(List<MemberOfCongress> senators) {
return senators.stream()
.collect(Collectors.groupingBy(MemberOfCongress::getParty, Collectors.counting()));
}
Apologies if you are not aware of the Java 8 syntax here. The stream functions are really just saying 'take all the senators, group them by party and then count them'. The key point is that you are returning a map from parties to integers representing the count of senators.
I would like to create a simple program that would output the atomic mass of any element entered. I am taking a Java course that I recently started so I don't know how to avoid using over 100 variables each with the elements atomic mass.
Also how could I get a if statement to use the name input from the user (which I know how to store in a string) and match it with one of the elements, in order to output the element's mass (corresponding to method used to store the multiple elements).
How can I condense this example code:
int carbon = 12;
int oxygen = 16;
int hydrogen = 1;
int sulfur = 32;
etc....
Sounds like your first step is to learn about the Map data structure. You can use it to associate the string names to integer values and then look them back up later.
Map<String, Integer> elements = new HashMap<String, Integer>();
elements.put("CARBON", 12);
elements.put("OXYGEN", 16);
//etc
Then if you have some input you can look up the number.
String userInput = scanner.next(); // or however you're getting input
Integer atomicWeight = elements.get(userInput.toUpper());
if (atomicWeight == null) //print element not found etc
Then once you have the program down and working you can learn about whatever technology is appropriate for loading the reference data from outside of the source code, whether that's a file or a database or a webservice or whatever.
I'd likely define an enum if confronted with this problem.
public enum Elements
{
HYDROGEN(1),
...
UNOBTANIUM(666);
public final int atomicWeight;
Elements(int atomicWeight)
{
this.atomicWeight = atomicWeight;
}
}
then to get the right element it's
String name = ...// from user input
Elements e = Elements.valueOf(name.toUpperCase());
I'd recommend using an enum as some have suggested, though i'd do it a little different. Maps have lots of overhead, and since your data is not dynamic it's not a great fit. Atomic mass should be a decimal value (double or BigDecimal depending on what you're using it for), not an int
public enum AtomicElement {
HYDROGEN(1.00794),
HELIUM(4.002602),
...;
private double atomicMass;
private AtomicElement (double atomicMass) {
this.atomicMass = atomicMass;
}
public int getAtomicNumber() {
return ordinal();
}
public double getAtomicMass() {
return atomicMass;
}
public static AtomicElement forAtomicNumber(int atomicNumber) {
return AtomicElement.values()[atomicNumber];
}
public static AtomicElement forElementName(String elementName) {
return AtomicElement.valueOf(elementName);
}
}
Then you can search by atomic number or element name
AtomicElement.forAtomicNumber(2);
AtomicElement.forElementName("CARBON");
This does however assume you're going to represent the entire periodic table with no gaps in the data, since it's using the ordinal() value as the atomic number. If you want gaps, you'll have to have an int field for the atomic number and your "forAtomicNumber" function will have to cycle through the "values()" to find the one with the given number.
You could even extend this if you wanted to include known isotopes, etc... if your requirements dictate that.
Because the atomic mass of the elements is not going to change at any point in your app, you should define them as final:
public class AtomicMass {
public static final int CARBON = 12;
public static final int OXYGEN = 16;
...
}
...or, you could use an enum:
public static enum Element {
carbon(12),
oxygen(16),
hydrogen(1),
sulfur(32);
private int atomicMass;
private Element( int mass ) {
this.atomicMass = mass;
}
}
If you order your elements sequentially (and add an UNKNOWN for 0) you wouldn't even need to explicitly provide the mass.
I like to group related data into arrays or arrayLists.
String[] elements = new String[# of elements in table];
Based on the position of the element you can have the atomic number.
Then I would loop through them to find any element or fill the array.
You can look into Java Scanner class to get input from user.
Create a class called Element that contains attributes like name, atomic number, etc. Each element will correspond to an instance of Element. You can then put all the Elementss in several maps, keyed by name, atomic number, etc. Use a factory class to instantiate and initialize the maps, and provide lookup methods.
If I understand you correctly you just want to only have 1 variable to store all the elements and their masses in which case I would recommend a HashMap. It will not really save on code lines but will let you do number 2 pretty easily. HashMaps store a set of key-value pairs and you can get the value if you have the key so this would create the list:
//Declare a new hashmap and initialize it
HashMap<String, Integer> elements = new HashMap<>();
//Add element information
elements.put("CARBON", 12);
elements.put("OXYGEN", 16);
elements.put("HYDROGEN", 1);
elements.put("SULFUR", 32);
Then for example to get user input from a dialog box and print the result to command line you do something like this:
//Collect user input and convert it to all upper case (in real life you would validate this)
String input = JOptionPane.showInputDialog(null, "Please enter an element name").toUpperCase();
//If element name exists in hashmap print its atomic weight
if(elements.containsKey(input.toUpperCase())){
System.out.println("Atomic Weight: " + elements.get(input));
}
Store your data in a file
Element, Weight
oxygen = 16
carbon, 12
.
.
.
Pseudocode:
//Read data file into a `Map<String, int>`
//Get user input
//Access map
//Output