Having trouble understanding how to maintain state using classes - java

I'm new to using OOP, I typically just put all my code in a single class and use methods. But I want to maintain state information and think classes are the best fit but I'm having trouble wrapping my head around it.
Say I have a list of items and I want to stop when the total sum of all previous items in the list equals X(in this case 10 so it takes item 1 + 2, then 2+3.etc..until it hits the threshold 10), I can use a method to calculate it but it involves me doing the entire process all over again when all I really need to do is increment by the last item and then see if my data exceeds the threshold. Here's my code so far but I know its not good because although it works its really just using the class as an independent method and recalculating on every loop. My goal is to,using this structure, reduce loops if not necessary to check thresholds.
Any suggestions?
Code:
public class LearningClassesCounter {
public static void main(String[] args) {
int[] list = new int[]{1,2,3,4,5,6,7,8,9,10};
int[] data_list = new int[list.length];
for (int current_location = 0; current_location<list.length;current_location++) {
//can only put commands in here. Nothing above.
Counter checker = new Counter(data_list);
System.out.println(checker.check_data(current_location));
for (int i =0; i<100; i++){
if (checker.check_data(current_location) == false) {
break;
}
data_list[current_location] = (list[current_location]+1); //this is just a random function, it could be any math function I just put it in here to show that some work is being done.
}
}
//its done now lets print the results
for (Integer item : data_list) {
System.out.println(item);
}
}
}
class Counter {
private int[] data_list;
private int total_so_far;
// create a new counter with the given parameters
public Counter(int[] data_list) {
this.data_list = data_list;
this.total_so_far = 0;
}
public boolean check_data(int current_location) {
// TODO Auto-generated method stub
int total_so_far = 0;
//System.out.println(total_so_far);
for (int item : data_list) {
total_so_far = item + total_so_far;
if (total_so_far >= 10) {
break;
}
}
if (total_so_far>=10) {
return false;
} else {
return true;
}
}
}
I don't need anyone to fix my code or anything(I want to do it myself, the code is just to give an idea of what I'm doing). I'm more interested in the flaw in my logic and maybe a way for me to better think about designing classes so I can apply them to my own situations better.

So the solution is that you do not update the data_list directly. Instead have a setter method in the Counter class that takes the index and value to update. It updates the value in the array and also updates a count value.
Something like this:
class Counter{
private final int[] list;
private count = 0;
private final maxCount = 10;
public Counter(int[] list){
this.list = list;
}
public boolean updateValueAndCheckPastMax(int index, int value){
list[index] = value;
count += value;
return count >= maxCount;
}
}

You are way over thinking this, and a counter class is not really necessary in this case.
I'm also interested as to why you'd be doing this line:
data_list[current_location] = (list[current_location]+1);
Do you want your data_list to be the same as list, but each value is incremented by 1?
If you are merely trying to return a sub-array of the values that are < 10, i would suggest just doing this in a for loop, and using an int as a counter.

Related

Java ArrayList trying to check if object with this name exists

I'm having a bit of trouble in my head trying to solve this:
I'm working on a "rankList", an arrayList made of "Score". Score it's the object that has the following atributes: name,wins,loses,draws. My class Ranking has an ArrayList of Score objects. To create a new Score object I just use the name (and set the rest to 0 since it's new). However I'm trying to check if the player's name it's already in rankList I don't have to create new but sum a win or lose or draw.
I have been reading arround that I have to override equals then others say I have to override contains... It's getting a big mess in my head. My fastest solution would be to write an "for" that goes arround the arrayList and use the getName().equals("name"); however this is getting too messi in my code. I have checkPlayer (if the palyer is in the list):
public boolean checkPlayer(String playerName) {
for (int i = 0; i < this.rankList.size(); i++) {
if (this.rankList.get(i).getName().equals(playerName)) {
return true;
}
}
return false;
}
then if I want to incrase the wins i have this :
public void incraseWins(String playerName) {
if (checkPlayer(playerName)) {
for (int i = 0; i < this.rankList.size(); i++) {
if (this.rankList.get(i).getName().equals(playerName)) {
this.rankList.get(i).setWins(this.rankList.get(i).getWins() + 1);
break;
}
}
} else {
createPlayer(playerName);
//more for to get to the player i'm looking for...
for (int i = 0; i < this.rankList.size(); i++) {
if (this.rankList.get(i).getName().equals(playerName)) {
this.rankList.get(i).setWins(this.rankList.get(i).getWins() + 1);
break;
}
}
}
So i guess there is a better way to do this... :/
ArrayList is not the right data structure here. To check if an element exists in the array you are searching the entire arraylist. Which means it's O(N).
To keep an array list is sorted order and do a binary search on it would definitely be faster as suggested in the comments. But that wouldn't solve all your problems either because insert into the middle would be slow. Please see this Q&A: When to use LinkedList over ArrayList?
One suggestion is to use a Map. You would then be storing player name, player object pairs. This would give you very quick look ups. Worst case is O(log N) i believe.
It's also worth mentioning that you would probably need to make a permanent record of these scores eventually. If so an indexed RDBMS would give you much better performance and make your code a lot simpler.
Try using a hashtable with a key, it would be much more efficient!
e..Why not using map<>.
a binary search is good idea if you must use List,code like this
List<Method> a= new ArrayList<>();
//some method data add...
int index = Collections.binarySearch(a, m);
Method f = a.get(index);
and class method is impl of Comparable,then override compareTo() method
public class Method implements Comparable<Method>{
........
#Override
public int compareTo(Method o) {
return this.methodName.compareTo(o.getMethodName());
}
if you don't want use binsearch,CollectionUtils in commons can help you
CollectionUtils.find(a, new Predicate() {
#Override
public boolean evaluate(Object object) {
return ((Method)object).getMethodName().equals("aaa");
}
});
in fact CollectionUtils.find is also a 'for'
for (Iterator iter = collection.iterator(); iter.hasNext();) {
Object item = iter.next();
if (predicate.evaluate(item)) {
return item;
}
}

What is the most efficient way to count the intersections between two sets (Java)?

Question Background
I am comparing two (at a time, actually many) text files, and I want to determine how similar they are. To do so, I have created small, overlapping groups of text from each file. I now want to determine the number of those groups from one file which are also from the other file.
I would prefer to use only Java 8 with no external libraries.
Attempts
These are my two fastest methods. The first contains a bunch of logic which allows it to stop if meeting the threshold is not possible with the remaining elements (this saves a bit of time in total, but of course executing the extra logic also takes time). The second is slower. It does not have those optimizations, actually determines the intersection rather than merely counting it, and uses a stream, which is quite new to me.
I have an integer threshold and dblThreshold (the same value cast to a double), which are the minimum percentage of the smaller file which must be shared to be of interest. Also, from my limited testing, it seems that writing all the logic for either set being larger is faster than calling the method again with reversed arguments.
public int numberShared(Set<String> sOne, Set<String> sTwo) {
int numFound = 0;
if (sOne.size() > sTwo.size()) {
int smallSize = sTwo.size();
int left = smallSize;
for (String item: sTwo) {
if (numFound < threshold && ((double)numFound + left < (dblThreshold) * smallSize)) {
break;
}
if (sOne.contains(item)) {
numFound++;
}
left--;
}
} else {
int smallSize = sOne.size();
int left = smallSize;
for (String item: sOne) {
if (numFound < threshold && ((double)numFound + left < (dblThreshold) * smallSize)) {
break;
}
if (sTwo.contains(item)) {
numFound++;
}
left--;
}
}
return numFound;
}
Second method:
public int numberShared(Set<String> sOne, Set<String> sTwo) {
if (sOne.size() < sTwo.size()) {
long numFound = sOne.parallelStream()
.filter(segment -> sTwo.contains(segment))
.collect(Collectors.counting());
return (int)numFound;
} else {
long numFound = sTwo.parallelStream()
.filter(segment -> sOne.contains(segment))
.collect(Collectors.counting());
return (int)numFound;
}
}
Any suggestions for improving upon these methods, or novel ideas and approaches to the problem are much appreciated!
Edit: I just realized that the first part of my threshold check (which seeks to eliminate, in some cases, the need for the second check with doubles) is incorrect. I will revise it as soon as possible.
If I understand you correctly, you have already determined which methods are fastest, but aren't sure how to implement your threshold-check when using Java 8 streams. Here's one way you could do that - though please note that it's hard for me to do much testing without having proper data and knowing what thresholds you're interested in, so take this simplified test case with a grain of salt (and adjust as necessary).
public class Sets {
private static final int NOT_ENOUGH_MATCHES = -1;
private static final String[] arrayOne = { "1", "2", "4", "9" };
private static final String[] arrayTwo = { "2", "3", "5", "7", "9" };
private static final Set<String> setOne = new HashSet<>();
private static final Set<String> setTwo = new HashSet<>();
public static void main(String[] ignoredArguments) {
setOne.addAll(Arrays.asList(arrayOne));
setTwo.addAll(Arrays.asList(arrayTwo));
boolean isFirstSmaller = setOne.size() < setTwo.size();
System.out.println("Number shared: " + (isFirstSmaller ?
numberShared(setOne, setTwo) : numberShared(setTwo, setOne)));
}
private static long numberShared(Set<String> smallerSet, Set<String> largerSet) {
SimpleBag bag = new SimpleBag(3, 0.5d, largerSet, smallerSet.size());
try {
smallerSet.forEach(eachItem -> bag.add(eachItem));
return bag.duplicateCount;
} catch (IllegalStateException exception) {
return NOT_ENOUGH_MATCHES;
}
}
public static class SimpleBag {
private Map<String, Boolean> items;
private int threshold;
private double fraction;
protected int duplicateCount = 0;
private int smallerSize;
private int numberLeft;
public SimpleBag(int aThreshold, double aFraction, Set<String> someStrings,
int otherSetSize) {
threshold = aThreshold;
fraction = aFraction;
items = new HashMap<>();
someStrings.forEach(eachString -> items.put(eachString, false));
smallerSize = otherSetSize;
numberLeft = otherSetSize;
}
public void add(String aString) {
Boolean value = items.get(aString);
boolean alreadyExists = value != null;
if (alreadyExists) {
duplicateCount++;
}
items.put(aString, alreadyExists);
numberLeft--;
if (cannotMeetThreshold()) {
throw new IllegalStateException("Can't meet threshold; stopping at "
+ duplicateCount + " duplicates");
}
}
public boolean cannotMeetThreshold() {
return duplicateCount < threshold
&& (duplicateCount + numberLeft < fraction * smallerSize);
}
}
}
So I've made a simplified "Bag-like" implementation that starts with the contents of the larger set mapped as keys to false values (since we know there's only one of each). Then we iterate over the smaller set, adding each item to the bag, and, if it's a duplicate, switching the value to true and keeping track of the duplicate count (I initially did a .count() at the end of .stream().allMatch(), but this'll suffice for your special case). After adding each item, we check whether we can't meet the threshold, in which case we throw an exception (arguably not the prettiest way to exit the .forEach(), but in this case it is an illegal state of sorts). Finally, we return the duplicate count, or -1 if we encountered the exception. In my little test, change 0.5d to 0.51d to see the difference.

What's the fastest way to initialize a large list of integers?

I need to pre-populate a List with a large number of integer values.
Is there are faster way to do this other than iteration?
Current Code:
class VlanManager {
Queue<Integer> queue = Lists.newLinkedList();
public VlanManager(){
for (int i = 1; i < 4094; i++) {
queue.add(i);
}
}
This code is in the constructor of a class that is created pretty frequently so I'd like this to be as efficient (read:performance not lines of code) as possible
4094 isnt to many items to loop but if it is getting called very frequently you might look at doing something with a static variable.
private static Integer[] theList;
static {
theList = new Integer[4094];
for (int i = 1; i < 4094; i++) {
theList[i-1] = i;
}
}
then make that list a List
Queue<Integer> intQue = new LinkedList(Arrays.asList(theList));
There is a danger of using this method if you have a list of mutable objects. Heres an example of what can happen. Integers are immutable so this doesnt actually apply to your question as it stands
class MyMutableObject {
public int theValue;
}
class Test {
private static MyMutableObject[] theList;
static {
theList = new MyMutableObject[4094];
for (int i = 1; i <= 4094; i++) {
theList[i-1] = new MyMutableObject();
theList[i-1].theValue = i;
}
}
public static void main(String [] args) {
Queue<MyMutableObject> que = new LinkedList(Arrays.asList(theList));
System.out.println(que.peek().theValue); // 1
// your actually modifing the same object as the one in your static list
que.peek().theValue = -100;
Queue<MyMutableObject> que2 = new LinkedList(Arrays.asList(theList));
System.out.println(que2.peek().theValue); // -100
}
}
#Bohemian Has some good points on using a static List instead of an array, while the performance gains are very small they are none the less performance gains. Also because the 'array' is actually only ever being used as a List not an array it should be declared as such.
private static List<Integer> theList;
static {
theList = new ArrayList(4094);
for (Integer i = 0; i < 4094; i++) {
theList.add(i+1);
}
}
The fastest way would be to create a reference list (initialized using an instance block - neatly wrapping it all up in one statement):
private static final List<Integer> LIST = new ArrayList<Integer>(4094) {{
for (int i = 1; i < 4094; i++)
LIST.add(i);
}};
Then in your constructor, initialize the queue using the copy constructor:
Queue<Integer> queue;
public VlanManager(){
queue = new LinkedList<Integer>(LIST);
}
You will not write a faster implementation than what's in the JDK.
I realize this question has already been answered. But I think one important answer is missing: The fastest way to initialize a LinkedList with the values 0..4093 is .. DON'T DO IT AT ALL. Especially if speed is an issue.
What you basically are doing is creating a structure consisting of 4093 Node elements each consiting of two pointers to prev/next element and one pointer to an Integer object. Each of this Nodes must be created (and free). In addition nearly each contained Integer must be created (and freed). 'Nearly' because Java uses a cache for Integer but normally (you can change this with system properties) in the range of -127..127.
This is a lot to do in order to get a simple list of integer and if used intensively gives the GC a lot to do afterwards.
That being said there are numerous possible ways of doing this in a more efficient way. But they depend on what your concrete usage pattern is. Just to name a few:
Use an Array: boolean [] inUse' and set the taken vlan-id totrue` if it's taken
Even better use a BitSet instead of the array
Don't store which vlan is free, but which vlan is taken. I think they tend to be free and so there are much more free as there are taken ones. (this means much less to keep track of).
If you insist on using a LinkedList don't initialize it with your class but have it already initialized. This depends on how much of them you would need. You could keep a pool of them. Or perhaps your codes allows reusage of old lists. (yes, you could sort them after usage.)
Surely there are more...
All of this methods require you to build your own 'Queue' interface. But perhaps this has not to be as rich as Java's. And it really isn't that difficult. If you really use this intensively you could reach perfomance improvement factor 10x-1000x++.
A possible implementation using BitSet with an instantiation cost of nearly nothing could be:
import java.util.BitSet;
import org.testng.annotations.Test;
public class BitSetQueue {
// Represents the values 0..size-1
private final BitSet bitset;
private final int size;
private int current = 0;
private int taken = 0;
public BitSetQueue( int size ){
this.bitset = new BitSet( size );
this.size = size;
this.current = size-1;
}
public int poll(){
// prevent endless loop
if( taken == size ) return -1;
// seek for next free value.
// can be changed according to policy
while( true ){
current = (current+1)%size;
if( ! bitset.get( current ) ){
bitset.set( current );
taken++;
return current;
}
}
}
public boolean free( int num ){
if( bitset.get( num ) ){
bitset.clear( num );
taken--;
return true;
}
return false;
}
#Test
public static void usage(){
BitSetQueue q = new BitSetQueue( 4094 );
for( int i = 0; i < 4094; i++ ){
assertEquals( q.poll(), i );
}
assertEquals( q.poll(), -1 ); // No more available
assertTrue( q.free( 20 ) );
assertTrue( q.free( 51 ) );
assertEquals( q.poll(), 20 );
assertEquals( q.poll(), 51 );
}
}

Find and print the product of all the entries in array

Okay I have tried to write a simple Java code in BlueJ, that finds and prints the product of all the entries in data such as if data is {1,2,3,4} then the result will be 24.
And my code is below:
public class Product {
public static int[] product(int[] a) {
int [] s = new int[a.length];
for (int i =0; i< a.length; i++)
s[i] = a[i]*a[i];
return s; //the definition of your method...
}
public static void main(String[] args) {
//calling the method to seek if compiles
int[] results = Product.product(new int[] { 1,2,3,4 });
//printing the results
System.out.println(java.util.Arrays.toString(results));
}
}
The above code is giving me the square of each number, which is not what I want to have, somehow I have modify the code that the result will be 24 but I couldn't figure it out, anyone knows how to do it?
First of all, if you are first writing Java it is important to know that variable, function and class names are quite important. Please note that having Product.product() is not a good idea, since the function name is almost the same as the class name. Anyway, regarding your code. Your code is indeed returning the square of your input, what you would want is the following:
public class Product {
public static int getProduct(int[] input) {
int total = 1;
for (int v : input) {
total *= v;
}
return total;
}
}
This will return an integer value with the product of your input array. This also uses a for-each loop instead of a regular for-loop for readability. Also you don't need the index in this case. Good luck with it!
First, your product method needs to return an int rather than an int [].
You need to maintain the product as a variable. You can set it to 1 initially, and then multiply it by each element of the a array in turn; then you just return this value.

How can I increment a variable on button click?

I'm trying to make a small game like thing for school. It's designed to help you learn your times tables. What I want is for the multiplier of the table to be random each time (5x8 then 5x3 then 5x9 etc).
I've got the generating of the numbers in control with an array as can be seen below
public static Integer[] generateNumbers()
{
Integer[] arr = new Integer[12];
for(int j = 0; j < arr.length; j++)
{
arr[j] = j+1;
}
Collections.shuffle(Arrays.asList(arr));
System.out.println(Arrays.asList(arr));
return arr;
}
How can I make it so that every time the user clicks a button, the next number in the array is selected, baring in mind that the button is declared in another class, and the ActionListener is also declared elsewhere?
Oh and the array is available class-wide as the function is declared like this:
public static Integer[] arr = generateNumbers();
Thematic answer
public class UnicornFrame extends JFrame {
private Integer[] poneyArr = MyClassThatGeneratesNumbers.generateNumbers();
private int poneyCounter = 0;
private JButton poneyButton;
public void poneyInit() {
System.out.println("Unicorns are poney magical friends!");
poneyButton = new JButton("OMG! Ponies!");
// Java 8 Lambdas! Yey!
poneyButton.addActionListener(e -> {
if (poneyCounter >= poneyArr.length) {
poneyArray = MyClassThatGeneratesNumbers.generateNumbers();
poneyCounter = 0;
}
Integer selected = poneyArr[poneyCounter++];
System.out.println("OMG! I have selected " + selected);
});
// other stuff
add(poneyButton, BorderLayout.CENTER);
}
}
The button int he separate class is not needed, the action listener will communicate with your array whenever its clicked, the easiest way I see is to put a public method int the array's class, that takes an index, which then increments the index, and returns the element stored at it.
Have fun coding, but these assignments are meant for you to scratch your head, try writing some code, and let us know if it breaks, rather than asking for general answers.

Categories