How to generate inner loops automatically in Java - java

I am trying to find a way to generate inner loops on demand (and have the depth as a variable).
In the following example, I am trying to generate a list of references such as jobo.2.2.2.2.2.2 where each .2 is added in the inner loop.
Here is what I have at the moment when I implement the new loop manually for 5 level of depth (i, j, k, l):
public void buildTaskList(){
String jobName ="jobo";
String last="";
long max=3;
List<String> tasks = new ArrayList<>();
for (long i = 1; i <= max; i++) {
for (long j = 1; j <= max; j++) {
if (j==max){
last="*";
tasks.add(jobName+"."+i+"."+j+last);
}else {
last="";
for (long k = 1; k <= max; k++) {
if (k==max){
last="*";
tasks.add(jobName+"."+i+"."+j+"."+k+last);
}else {
last="";
for (long l = 1; l <= max; l++) {
if (l==max){
last="*";
tasks.add(jobName+"."+i+"."+j+"."+k+"."+l+last);
}else{
last="";
for (long m = 1; m <= max; m++) {
if (m==max){
last="*";
tasks.add(jobName+"."+i+"."+j+"."+k+"."+l+"."+m+last);
}else{
last="";
for (long n = 1; n <= max; n++) {
if (n==max)last="*";else last="";
tasks.add(jobName+"."+i+"."+j+"."+k+"."+l+"."+m+"."+n+last);
}
}
}
}
}
}
}
}
}
}
tasks.add(jobName+"."+(max+1)+last);
System.out.println(tasks);
}
The result here is:
jobo.1.1.1.1.1.1, jobo.1.1.1.1.1.2, jobo.1.1.1.1.1.3*, jobo.1.1.1.1.2.1, jobo.1.1.1.1.2.2, jobo.1.1.1.1.2.3*, jobo.1.1.1.1.3*, jobo.1.1.1.2.1.1, jobo.1.1.1.2.1.2, jobo.1.1.1.2.1.3*, jobo.1.1.1.2.2.1, jobo.1.1.1.2.2.2, jobo.1.1.1.2.2.3*, jobo.1.1.1.2.3*, jobo.1.1.1.3*, jobo.1.1.2.1.1.1, jobo.1.1.2.1.1.2, jobo.1.1.2.1.1.3*, jobo.1.1.2.1.2.1, jobo.1.1.2.1.2.2, jobo.1.1.2.1.2.3*, jobo.1.1.2.1.3*, jobo.1.1.2.2.1.1, jobo.1.1.2.2.1.2, jobo.1.1.2.2.1.3*, jobo.1.1.2.2.2.1, jobo.1.1.2.2.2.2, jobo.1.1.2.2.2.3*, jobo.1.1.2.2.3*, jobo.1.1.2.3*, jobo.1.1.3*, jobo.1.2.1.1.1.1, jobo.1.2.1.1.1.2, jobo.1.2.1.1.1.3*, jobo.1.2.1.1.2.1, jobo.1.2.1.1.2.2, jobo.1.2.1.1.2.3*, jobo.1.2.1.1.3*, jobo.1.2.1.2.1.1, jobo.1.2.1.2.1.2, jobo.1.2.1.2.1.3*, jobo.1.2.1.2.2.1, jobo.1.2.1.2.2.2, jobo.1.2.1.2.2.3*, jobo.1.2.1.2.3*, jobo.1.2.1.3*, jobo.1.2.2.1.1.1, jobo.1.2.2.1.1.2, jobo.1.2.2.1.1.3*, jobo.1.2.2.1.2.1, jobo.1.2.2.1.2.2, jobo.1.2.2.1.2.3*, jobo.1.2.2.1.3*, jobo.1.2.2.2.1.1, jobo.1.2.2.2.1.2, jobo.1.2.2.2.1.3*, jobo.1.2.2.2.2.1, jobo.1.2.2.2.2.2, jobo.1.2.2.2.2.3*, jobo.1.2.2.2.3*, jobo.1.2.2.3*, jobo.1.2.3*, jobo.1.3*, jobo.2.1.1.1.1.1, jobo.2.1.1.1.1.2, jobo.2.1.1.1.1.3*, jobo.2.1.1.1.2.1, jobo.2.1.1.1.2.2, jobo.2.1.1.1.2.3*, jobo.2.1.1.1.3*, jobo.2.1.1.2.1.1, jobo.2.1.1.2.1.2, jobo.2.1.1.2.1.3*, jobo.2.1.1.2.2.1, jobo.2.1.1.2.2.2, jobo.2.1.1.2.2.3*, jobo.2.1.1.2.3*, jobo.2.1.1.3*, jobo.2.1.2.1.1.1, jobo.2.1.2.1.1.2, jobo.2.1.2.1.1.3*, jobo.2.1.2.1.2.1, jobo.2.1.2.1.2.2, jobo.2.1.2.1.2.3*, jobo.2.1.2.1.3*, jobo.2.1.2.2.1.1, jobo.2.1.2.2.1.2, jobo.2.1.2.2.1.3*, jobo.2.1.2.2.2.1, jobo.2.1.2.2.2.2, jobo.2.1.2.2.2.3*, jobo.2.1.2.2.3*, jobo.2.1.2.3*, jobo.2.1.3*, jobo.2.2.1.1.1.1, jobo.2.2.1.1.1.2, jobo.2.2.1.1.1.3*, jobo.2.2.1.1.2.1, jobo.2.2.1.1.2.2, jobo.2.2.1.1.2.3*, jobo.2.2.1.1.3*, jobo.2.2.1.2.1.1, jobo.2.2.1.2.1.2, jobo.2.2.1.2.1.3*, jobo.2.2.1.2.2.1, jobo.2.2.1.2.2.2, jobo.2.2.1.2.2.3*, jobo.2.2.1.2.3*, jobo.2.2.1.3*, jobo.2.2.2.1.1.1, jobo.2.2.2.1.1.2, jobo.2.2.2.1.1.3*, jobo.2.2.2.1.2.1, jobo.2.2.2.1.2.2, jobo.2.2.2.1.2.3*, jobo.2.2.2.1.3*, jobo.2.2.2.2.1.1, jobo.2.2.2.2.1.2, jobo.2.2.2.2.1.3*, jobo.2.2.2.2.2.1, jobo.2.2.2.2.2.2, jobo.2.2.2.2.2.3*, jobo.2.2.2.2.3*, jobo.2.2.2.3*, jobo.2.2.3*, jobo.2.3*, jobo.3.1.1.1.1.1, jobo.3.1.1.1.1.2, jobo.3.1.1.1.1.3*, jobo.3.1.1.1.2.1, jobo.3.1.1.1.2.2, jobo.3.1.1.1.2.3*, jobo.3.1.1.1.3*, jobo.3.1.1.2.1.1, jobo.3.1.1.2.1.2, jobo.3.1.1.2.1.3*, jobo.3.1.1.2.2.1, jobo.3.1.1.2.2.2, jobo.3.1.1.2.2.3*, jobo.3.1.1.2.3*, jobo.3.1.1.3*, jobo.3.1.2.1.1.1, jobo.3.1.2.1.1.2, jobo.3.1.2.1.1.3*, jobo.3.1.2.1.2.1, jobo.3.1.2.1.2.2, jobo.3.1.2.1.2.3*, jobo.3.1.2.1.3*, jobo.3.1.2.2.1.1, jobo.3.1.2.2.1.2, jobo.3.1.2.2.1.3*, jobo.3.1.2.2.2.1, jobo.3.1.2.2.2.2, jobo.3.1.2.2.2.3*, jobo.3.1.2.2.3*, jobo.3.1.2.3*, jobo.3.1.3*, jobo.3.2.1.1.1.1, jobo.3.2.1.1.1.2, jobo.3.2.1.1.1.3*, jobo.3.2.1.1.2.1, jobo.3.2.1.1.2.2, jobo.3.2.1.1.2.3*, jobo.3.2.1.1.3*, jobo.3.2.1.2.1.1, jobo.3.2.1.2.1.2, jobo.3.2.1.2.1.3*, jobo.3.2.1.2.2.1, jobo.3.2.1.2.2.2, jobo.3.2.1.2.2.3*, jobo.3.2.1.2.3*, jobo.3.2.1.3*, jobo.3.2.2.1.1.1, jobo.3.2.2.1.1.2, jobo.3.2.2.1.1.3*, jobo.3.2.2.1.2.1, jobo.3.2.2.1.2.2, jobo.3.2.2.1.2.3*, jobo.3.2.2.1.3*, jobo.3.2.2.2.1.1, jobo.3.2.2.2.1.2, jobo.3.2.2.2.1.3*, jobo.3.2.2.2.2.1, jobo.3.2.2.2.2.2, jobo.3.2.2.2.2.3*, jobo.3.2.2.2.3*, jobo.3.2.2.3*, jobo.3.2.3*, jobo.3.3*, jobo.4*
Anyone knows how this can be simplified and controlled by a variable int depth=123; for example?
Thanks

This option avoids recursion, and simply counts as you would when deciding the next element in the sequence:
private static class LevelGenerator implements Iterator<String> {
private int[] current; // min,min,min => min,min,min+1 => ... max,max,max
private int min, max; // at each position in current[] array
private String next; // to be returned when next() is called
public LevelGenerator(int levels, int min, int max) {
this.current = new int[levels];
for (int i=0; i<levels; i++) this.current[i] = min;
this.next = output();
this.min = min;
this.max = max;
}
/**
* Int array to string
*/
private String output() {
StringBuilder sb = new StringBuilder();
for (int i : current) sb.append("." + i);
return sb.toString();
}
/**
* Updates current and next
* counts as a human would: increments the last index that is not yet `max`,
* and then places all elements after it to `min`
*/
private String step() {
for (int i=current.length-1; i>=0; i--) {
if (current[i] < max) {
current[i] ++;
for (int j=i+1; j<current.length; j++) {
current[j] = min;
}
return output(); // next step is ready
}
}
return null; // no next step
}
#Override
public String next() {
if (next == null) throw new IllegalStateException("iteration is finished");
String output = next;
next = step();
return output;
}
#Override
public boolean hasNext() {
return next != null;
}
}
public static void main(String ... args) {
LevelGenerator l = new LevelGenerator(3, 1, 4);
while (l.hasNext()) {
System.out.println("job" + l.next());
}
}
The output for this example would be:
job.1.1.1
job.1.1.2
job.1.1.3
job.1.1.4
job.1.2.1
job.1.2.2
job.1.2.3
job.1.2.4
job.1.3.1
job.1.3.2
job.1.3.3
job.1.3.4
job.1.4.1
job.1.4.2
job.1.4.3
job.1.4.4
job.2.1.1
...
job.4.4.4

You can use Recursion (see wiki https://en.wikipedia.org/wiki/Recursion_(computer_science))
for example (draft, not checking)
#Test
public void buildTaskList1() {
String jobName ="job";
int depth=5;
int max=3;
List<String> tasks = new ArrayList<>();
for (long i = 1; i <= max; i++) {
buildTaskListRecursion(max, depth, tasks, jobName + "."+i);
}
tasks.add(jobName+"."+(max+1)+"*");
}
public void buildTaskListRecursion(int max,int depth, List<String> tasks, String jobName){
String last="";
for (long j = 1; j <= max; j++) {
if (j==max){
last="*";
tasks.add(jobName+"."+j+last);
}else {
depth--;
if(depth > 0) {
buildTaskListRecursion(max, depth, tasks, jobName+"."+j);
} else {
tasks.add(jobName+"."+j);
}
}
}
}

Yes
1. Support indexes
Create a stack of indexes of the size of depth.
2. Handle the levels properly
You need a currentDepth index to know where you were. This is 0 at first. Whenever an item is increased, push a new item to the stack with 0 as index. Whenever an item is going beyond max, pop it from the stack and increment the previous element. When the first element is popped, you completed all the work
3. You will need to logically know where you were.
Alternatively you could generate code
But that's much more complicated.
EDIT
In agreement with Bdzzaid's legitimate request, I will briefly talk about the Composite Design Pattern. First, let's see a diagram from the page he shared with us:
Source: https://dzone.com/articles/composite-design-pattern-in-java-1
That's a good read I can wholeheartedly recommend to future readers. The idea is that we use the composition of very similar components in a tree-like manner. The pattern is applied on a stack in our case, which can be thought about as a tree having a single branch in all cases. The reason this is beneficial to think about in this way is that we might want to add support for multiple loops, maybe even in an assymmetryc manner at some point. Now, the components are the levels/indexes in our case and they, together form a composition of the stack (or, in more general terms, the tree).
This pattern can be reused in many different situations, so it is advisable to get familiar with it if you not already have.

Related

Java - outOfMemory - Heap Space

So I'm trying to complete an exercise where I've been asked to implement a method that does a binary search in an ArrayList of objects. From the exercise:
Binary search
In the Main-class, implement a method public static int binarySearch(ArrayList<Book> books, int searchedId), which searches the list it received as a parameter, for a book with an id variable that matches the value of searchedId variable it received as a parameter. If that book is found the method, should return the index it's located at, in the list it received as a parameter. If the book isn't found, the method should return the value -1.
The method must be implemented as a binary search, which assumes the list is ordered. You should also assume, that the ids towards the beginning of the list, are always smaller than the ids towards the end of the list.
I have created two methods, one to check whether the arraylist is sorted (isItSorted) and the other one that will perform the binary search if the aforementioned method evaluates to true (binarySearch). Please see below:
public static boolean isItSorted(ArrayList<Book> books) {
ArrayList<String> boo = new ArrayList<>();
String isItSorted = "";
for (int i = 0; i < books.size(); i++) {
for (int j = i + 1; j < books.size(); j++) {
if (books.get(i).getId() < books.get(j).getId()) {
isItSorted = "true";
boo.add(isItSorted);
} else {
isItSorted = "false";
boo.add(isItSorted);
}
}
}
if (!(boo.contains("false"))) {
return true;
}
return false;
}
public static int binarySearch(ArrayList<Book> books, long searchedId) {
if (searchedId < 0 || books.isEmpty()) {
return -1;
} else if (isItSorted(books)) {
int start = 0;
int end = books.size() - 1;
int middle = (start + end) / 2;
if (books.get(middle).getId() == searchedId) {
return middle;
} else if (books.get(middle).getId() > searchedId) {
end = middle - 1;
} else if (books.get(middle).getId() < searchedId) {
start = middle + 1;
}
while (start <= end) {
if (books.get(start).getId() == searchedId) {
return start;
}
start++;
}
}
return -1;
}
Inside these java files, there's a test package that tests whether my solution is correct or not. While 95% of the tests are successful, when it reaches the method below (where it compares the time of execution compared to my other method (linear search)), I get the error Java outOfMemory heap Space.
I use NetBeans. I've already tried the JVM commands.
My solution seems to work with every number of objects I've tried, so perhaps there's something wrong with the test code below?
#Test
#Points("07-05.2")
public void binarySearchIsFasterThanLinearSearch() throws Throwable {
ArrayList<Book> books = generateBooks(10000);
Collections.sort(books, (k1, k2) -> k1.getId() - k2.getId());
int searched = 1000001;
long bSearchStart = System.nanoTime();
int binarySearchId = Searching.binarySearch(books, searched);
long bSearchEnd = System.nanoTime();
assertTrue("When binary search does not find what was searched for, it must return -1", binarySearchId == -1);
long lSearchStart = System.nanoTime();
int linearSearchId = Searching.linearSearch(books, searched);
long lSearchEnd = System.nanoTime();
assertTrue("When linear search does not find what was searched for, it must return -1", linearSearchId == -1);
long bSearchTime = bSearchEnd - bSearchStart;
long lSearchTime = lSearchEnd - lSearchStart;
assertTrue("When there are 10000 books to search, and the searched book is not found, binary search should be a lot faster than linear search. Current this isn't so", bSearchTime * 2 < lSearchTime);
}
ArrayList<String> boo = new ArrayList<>();
String isItSorted = "";
for (int i = 0; i < books.size(); i++) {
for (int j = i + 1; j < books.size(); j++) {
if (books.get(i).getId() < books.get(j).getId()) {
isItSorted = "true";
boo.add(isItSorted);
} else {
isItSorted = "false";
boo.add(isItSorted);
}
}
}
Adds on the order of 100 million items to the ArrayList boo.
If you want to check if something is sorted you can use much simpler code:
Book prev = books[0];
for (int i = 1; i < books.size(); i++) {
if (prev.getId() > books[i].getId())
return false;
}
return true;
But you shouldn't need to call it inside binarySearch() because that will defeat the purpose of binarySearch() and make it as slow as linearSearch().

String index out of range in Java

I am aware there are multiple threads like my assignment below, but I just can't figure it out. I can't exactly figure out the mistake. Help would be appreciated.
I am trying to do this program:
Everything works fine unless I input the same chains or similar (for example ACTG and ACTG or ACTG and ACTGCCCC), when it tells me
string index out of range
This is that part of my code:
int tries=0;
int pos=-1;
int k;
for (int i=0; i<longDNA.length(); i++) {
tries=0;
k=i;
for (int j=0; j<shortDNA.length(); j++) {
char s=shortDNA.charAt(j);
char l=longDNA.charAt(k);
if (canConnect(s,l)) {
tries+=1;
k+=1;
}
}
if (tries==shortDNA.length()-1) {
pos=i-1;
break;
}
}
Let's call the two DNA strings longer and shorter. In order for shorter to attach somewhere on longer, a sequence of bases complementary to shorter must be found somewhere in longer, e.g. if there is ACGT in shorter, then you need to find TGCA somewhere in longer.
So, if you take shorter and flip all of its bases to their complements:
char[] cs = shorter.toCharArray();
for (int i = 0; i < cs.length; ++i) {
// getComplement changes A->T, C->G, G->C, T->A,
// and throws an exception in all other cases
cs[i] = getComplement(cs[i]);
}
String shorterComplement = new String(cs);
For the examples given in your question, the complement of TTGCC is AACGG, and the complement of TGC is ACG.
Then all you have to do is to find shorterComplement within longer. You can do this trivially using indexOf:
return longer.indexOf(shorterComplement);
Of course, if the point of the exercise is to learn how to do string matching, you can look at well-known algorithms for doing the equivalent of indexOf. For instance, Wikipedia has a category for String matching algorithms.
I tried to replicate your full code as fast as I could, I'm not sure if I fixed the problem but you don't get any errors.
Please try it and see if it works.
I hope you get this in time and good luck!
import java.util.Arrays;
public class DNA {
public static void main(String[] args) {
System.out.println(findFirstMatchingPosition("ACTG", "ACTG"));
}
public static int findFirstMatchingPosition(String shortDNA, String longDNA) {
int positionInLong = 0;
int positionInShort;
while (positionInLong < longDNA.length()) {
positionInShort = 0;
while(positionInShort < shortDNA.length()) {
String s = shortDNA.substring(positionInShort, positionInShort + 1);
if(positionInShort + positionInLong + 1 > longDNA.length()) {
break;
}
String l = longDNA.substring(positionInShort + positionInLong, positionInShort + positionInLong + 1);
if(canConnect(s, l)) {
positionInShort++;
if(positionInShort == shortDNA.length()) {
return positionInLong;
}
} else {
break;
}
}
positionInLong++;
if(positionInLong == longDNA.length()) {
return -1;
}
}
return -1;
}
private static String[] connections = {
"AT",
"TA",
"GC",
"CG"
};
private static boolean canConnect(String s, String l) {
if(Arrays.asList(connections).contains((s+l).toUpperCase())) {
return true;
} else {
return false;
}
}
}
I finally changed something with the k as Faraz had mentioned above to make sure the charAt does not get used when k overrides the length of the string and the program worked marvelously!
The code was changed to the following:
int tries=0;
int pos=-1;
int k;
for (int i=0; i<longDNA.length(); i++) {
tries=0;
k=i;
for (int j=0; j<shortDNA.length(); j++) {
if (k<longDNA.length()) {
char s=shortDNA.charAt(j);
char l=longDNA.charAt(k);
if ((s=='A' && l=='T') || (s=='T' && l=='A') || (s=='G' && l=='C') || (s=='C' && l=='G')) {
tries+=1;
k+=1;
}
}
}
if (tries==shortDNA.length()) {
pos=i;
break;
}
}
I am not sure how aesthetically pleasing or correct this excerpt is but - it completely solved my problem, and just 2 minutes before the deadline! :)
A huge thanks to all of you for spending some time to help me!!

Randomize String Array and display all of the values

I'm making a card game, and I've arrived at the shufflin' time.
I've to shuffle a few cards (that are chosen before from the user, so they're not always the same amount) and then display them to the user one by one.
As I'm still developing the game's logic I'm displaying cards' name by changing a button text.
But I get stuck when I try to get the cards' name and set them as the button's text.
What happens is me gettin' a blank button or just with "Masons" or "Villager" String. Infact if I check the log I see that all the others cards(characters) get displayed as "null".
This is how I tried to achieve the goal (Yes I'm a newbie):
This is the head:
int demoniac;
int guard;
int masons;
int medium;
int mythomaniac;
int owl;
int villager;
int werehamster;
int all;
int i;
int t;
String[] characters = new String[24];
Button randomButton;
My method to addAll the cards(characters):
public void addAll(){
for(i = 0; i < all; i++){
add(demoniac, "Demoniac");
add(guard, "Guard");
add(medium, "Medium");
add(mythomaniac, "Mythomaniac");
add(owl, "Owl");
add(werehamster, "Werehamster");
add(villager, "Villager");
add(masons, "Masons");
}
}
My method to add and manage the various types of cards(characters):
public int add(int character, String name){
if(character != 0 && name == "Villager"){
for(t = 0; t < character; t++){
i+=t;
characters[i] = name;}
}
else if(character == 2 && name == "Masons"){
characters[i] = name;
i++;
characters[i] = name;
Toast.makeText(randomSelection.this, "works", Toast.LENGTH_SHORT).show();
}else if(character != 0){
characters[i] = name;
}
return i;
}
To randomize:
public void randomize(){
Collections.shuffle(Arrays.asList(characters));
for (int s = 1; s < characters.length; s++)
{
System.out.println(characters[s]);
}
}
The method to display a different card(character) each time the user clicks the button:
public void show(View view){
for (int s = 1; s < characters.length; s++)
{
randomButton.setText(characters[s]);
}
}
EDIT:
I've noticed the no sense for loop I've done, by the way you should know although most of the characters are only 1 of their kind (demoniac, guard, etc..) there are 2 Masons and from 5 to 12 Villagers, so We need to retrieve these ints and add as much Strings to the Array as much we're told from those ints.
Example: If I get 6 Villagers, I've to add the String "Villager" 6 times into the String Array.
Then I've set that s value to 1 'cause I've to display the first
String ([0]) as soon as the Activity gets started, so on the OnCreate() method.
Maybe I'm wrong, if so I please you to correct me!
Getting a blank button or just with "Masons" or "Villager" String
That is because you only set the Button's text with the last element of the list. Which is either null or "Masons" (not seeing how it could be "Villager").
for (int s = 1; s < characters.length; s++)
{
randomButton.setText(characters[s]);
}
If I check the log I see that all the others cards(characters) get displayed as "null"
You only set position 0 of your array. For example, you don't initialize the positions, so these int values default to 0.
int demoniac;
int guard;
int all;
Then
for(i = 0; i < all; i++){
add(demoniac, "Demoniac");
add(guard, "Guard");
Really, that loop shouldn't be entered because all equals 0.
Additionally
Collections are zero-indexed, so this doesn't print element 0. You need to set int s = 0;.
for (int s = 1; s < characters.length; s++)
It isn't clear to me what the add(int character, String name) method is returning, but if you explain it, I will update this answer.
I believe this code fulfills most of what you are trying to achieve
// Where the characters are stored
private ArrayList<String> characters;
public void initDeck() {
if (characters == null)
characters = new ArrayList<String>();
// Extract the numbers if you actually need them, otherwise, they just are constants
addCharacter("Demoniac", 1, characters);
addCharacter("Guard", 1, characters);
addCharacter("Medium", 1, characters);
addCharacter("Mythomaniac", 1, characters);
addCharacter("Owl", 1, characters);
addCharacter("Werehamster", 1, characters);
addCharacter("Villager", 5, characters);
addCharacter("Masons", 1, characters);
}
public void addCharacter(String name, int amount, ArrayList<String> cards) {
if (amount < 0) {
throw new IllegalArgumentException("Must add a non-negative number of characters for " + name);
}
// Don't use '==' for Strings
if (name.equals("Villager")) {
if (amount != 5 || amount != 12) {
throw new IllegalArgumentException("There can only be 5 or 12 " + name);
}
}
for (int i = 0; i < amount; i++) {
cards.add(name);
}
}
public int searchCharacters(String character, ArrayList<String> cards) {
return cards.indexOf(character);
}
public Map<String, Integer> getAllCharacterPositions() {
Map<String, Integer> allPositions = new LinkedHashMap<String, Integer>();
for (int i = 0; i < characters.size(); i++) {
allPositions.put(characters.get(i), i);
}
return allPositions;
}
void run() {
// initialize the characters
initDeck();
// shuffle them
Collections.shuffle(characters);
// print them all out
for (int i = 0; i < characters.size(); i++) {
System.out.printf("%d: %s\n", i, characters.get(i));
}
// Find the position of a character
System.out.println();
String findCharacter = "Owl";
// Option 1 -- always linear search lookup
System.out.printf("%d: %s\n", searchCharacters(findCharacter, characters), findCharacter);
// Option 2 -- one-time linear scan, constant lookup
Map<String, Integer> positions = getAllCharacterPositions();
System.out.printf("%d: %s\n", positions.get(findCharacter), findCharacter);
// Get a random character
System.out.println();
Random rand = new Random(System.currentTimeMillis());
int randPos = rand.nextInt(characters.size());
System.out.printf("%d: %s\n", randPos, characters.get(randPos));
// randomButton.setText(characters.get(randPos));
}
Given the array is already shuffled, just look at the first card:
public void show(View view){
randomButton.setText(characters[0]);
}
If you want to navigate that deck I suggest you put the shuffled list in to a Queue, where you can look at the next card (peek) or take the next card (poll):
private static Queue<string> buildNewShuffledDeck(String[] characters){
List<String> shuffledCharacterList = new ArrayList<String>(characters);
Collections.shuffle(shuffledCharacterList);
Queue<string> deck = new ArrayDeque(shuffledCharacterList);
return deck;
}
public void show(View view){
String nextCard = deck.peek();
if (nextCard != null)
randomButton.setText(nextCard);
else
//deck is empty...
}
Then to take from the deck, say on the random button click:
String nextCard = deck.poll();
General advice on arrays: Stop using them in favor of other data types that are far more useful and interchangeable.
Then next step advice, make a class that represents a Card and stop using Strings, the string you currently have is just one property of a card.
You are just displaying the last character name that you add
Replace with this
public void show(View view){
Random r = new Random(System.currentTimeMillis());
randomButton.setText(characters[r.nexInt(characters.length)])
}

Where can I use threads to improve these methods?

Okay so for my project in my CSC330 class I am supposed to use threads to quickly find the answer to queries in a massive data set. Each item in the array is a user and the string is a collection of sites they visited on a website identified by number.
Example (the array is String users[])
users[1] = "1 4 5 7" users[2] = "1 2 7 17 10" users[3] = "6"
The queries are:
are there more than ___ users who looked at X
What percent of users looked at X
Are there more users who looked at X than Y
How many users viewed X ____ number of times
What percent of users looked at X more than Y
there are about a million users in this array and we had to solve the following queries without threads on a smaller scale version of the data for testing. All of mine work. Now I need to switch to the massive text file and I need to use threads to increase the speed. I'm wondering where it would be beneficial and how I could implement these threads. I will supply my code for solving each query. I'm thinking that I could use multiple threads to go through parts of the array at the same time but I'm not sure how to execute this.
public boolean query1(String num, String pageName){
if(num == null){
return false;
}
else
{
int userCount = 0;
int pageNum = convert(pageName);
System.out.println(pageNum);
String pageNumString = Integer.toString(pageNum);
System.out.println(pageNumString);
for(int i = 0; i < users.length; i++ )
{
for(String entry : users[i].split(" "))
{
if(entry.equals(pageNumString))
{
userCount++;
break;
}
}
}
if(userCount > Integer.parseInt(num)){
return false;
}
else{
return true;
}
}
}
public float query2(String pageName){
int userCount = 0;
int pageNum = convert(pageName);
String pageNumString = Integer.toString(pageNum);
for(int i = 0; i < users.length; i++ )
{
for(String entry : users[i].split(" "))
{
if(entry.equals(pageNumString))
{
userCount++;
break;
}
}
}
float percentage = (userCount*100.0f)/users.length;
return percentage;
}
public boolean query3(String pageName, String pageName2){
int userCount1 = 0;
int userCount2 = 0;
String pageNumString = Integer.toString(convert(pageName));
String pageNumString2 = Integer.toString(convert(pageName2));
for(int i = 0; i < users.length; i++ )
{
for(String entry : users[i].split(" "))
{
if(entry.equals(pageNumString))
{
userCount1++;
break;
}
}
for(String entry : users[i].split(" "))
{
if(entry.equals(pageNumString2))
{
userCount2++;
break;
}
}
}
return userCount1 > userCount2;
}
public int query4(String pageName, int numTimes){
int userCount = 0;
String pageNumString = Integer.toString(convert(pageName));
for(int i = 0; i < users.length; i++ )//runs through each user
{ int pageCount = 0;
for(String entry : users[i].split(" "))// runs through each user's pages
{
if(entry.equals(pageNumString))
{
pageCount++; // each time page is found page count increments 1
}
} // once done running through user's pages
if(pageCount == numTimes){ // check if the number of pages is equal to the number given
userCount++; // if so increment userCount
}
}
return userCount;
}
public float query5(String pageName, String pageName2){
int viewedMore = 0;
int userCount1 = 0;
int userCount2 = 0;
String pageNumString = Integer.toString(convert(pageName));
String pageNumString2 = Integer.toString(convert(pageName2));
for(int i = 0; i < users.length; i++ )
{
for(String entry : users[i].split(" ")){
userCount1 = 0;
userCount2 = 0;
if(entry.equals(pageNumString))
{
userCount1++;
break;
}
}
for(String entry : users[i].split(" "))
{
if(entry.equals(pageNumString2))
{
userCount2++;
break;
}
}
if(userCount1 > userCount2){
viewedMore++;
}
}
return viewedMore*100.0f/users.length;
}
At the very least, in query3 and query5 you can spawn off threads for each of the two inner for-loops; there's no reason they must be run sequentially. And for any of the query functions, you can certainly split the array into sections. Since your data is growing large, that approach will most likely be faster than iterating over the data with the main thread.
I would suggest providing the threads contiguous segments (e.g. index 0 to N-1; N to N+N-1 etc). This previous StackOverflow answer provides good reasoning why such an approach is most efficient. Once you get something working, you can play around with the number of threads to optimize.
edit to address your comment below
One approach would be to implement the strategy pattern, such that each of your Query are interchangeable across a client, where an executeQuery() call is the interface method. Think of having a client's call look something like
interface Query {
boolean executeQuery();
}
// client code...
Client client = new Client(...);
client.setQuery(new Query3(String num, String pageNum));
client.query(); // calls query.executeQuery();
Within the concrete Query classes, you can define individual behaviors of what the threads would do. This is a rough example:
public Query3 implements Query {
Query3(String pageNum`, String pageNum2) {
this.pageNum1=pageNum1;
this.pageNum2=pageNum2;
}
boolean executeQuery() {
for(int i = 0; i < users.length; i++ ) {
SearchThread first = new SearchThread(pageNum1);
SearchThread second = new SearchThread(pageNum2);
first.run();
second.run();
}
first.join();
second.join();
return first.userCount > second.userCount;
}
SearchThread extends Thread {
String pageNumString;
int userCount;
SearchThread(String pageNumString) {
this.pageNumString=pageNumString;
}
public void run() {
// do your search over this segment of the array, adding up userCounts
}
Here is another StackOverflow question that describes how to run multiple threads over a single array, with some boilerplate code to use.

I have to return a value from a function that is called multiple times and I am unable to do that

I am stuck.
The following function is supposed to return currVm, an integer. But if I make a return I will break the loop and next time when this function is called,the same process will begin again.
What shall I do, so that I continue from where I left off ? I tried making static variables but I that didn't help me.
#Override
public int getNextAvailableVm() {
Set<String> dataCenters = confMap.keySet();
for (String dataCenter : dataCenters) {
LinkedList<DepConfAttr> list = confMap.get(dataCenter);
Collections.sort(list, new MemoryComparator());
int size = list.size() - 1;
int count = 0;
while(size >= 0) {
DepConfAttr dca = (DepConfAttr)list.get(count);
int currVm = dca.getVmCount();
int c = 0;
while(c <= currVm) {
allocatedVm(currVm);
c++;
return currVm;
}
count++;
size--;
}
}
return 0;
}
The for-each loop assigns a new data center that acts as a key for the confMap.The list that I get as a value, is sorted.Then a loop is run till it escapes its size.Inside this while loop, another while loop is run from where a function named allocatedVm of the inherited class is called. A parameter named currVm is passed to it.
This is the variable that I need to return. What shall I do to return this variable ? I have to start from I left off. I mean the next call should appear to be the next step, whatever it was, while executing the loop.
Add List<Integer> object to your class, and change your method as follows:
private Iterator<Integer> availableVms = null;
#Override
public int getNextAvailableVm() {
if (availableVms != null) {
if (availableVms.hasNext()) {
return availableVms.next();
}
return 0;
}
List<Integer> tmp = new ArrayList<Integer>();
Set<String> dataCenters = confMap.keySet();
for (String dataCenter : dataCenters) {
LinkedList<DepConfAttr> list = confMap.get(dataCenter);
Collections.sort(list, new MemoryComparator());
int size = list.size() - 1;
int count = 0;
while(size >= 0) {
DepConfAttr dca = (DepConfAttr)list.get(count);
int currVm = dca.getVmCount();
int c = 0;
while(c <= currVm) {
allocatedVm(currVm);
c++;
tmp.add(currVm);
}
count++;
size--;
}
}
availableVms = tmp.iterator();
return availableVms.hasNext() ? availableVms.next() : 0;
}
The idea is to pre-generate the entire list, and store its iterator for future use. Before entering the method you check if the availableVms iterator has been prepared. If it has been prepared, grab the next item off of it if it's available; otherwise, return zero.
If the list has not been prepared yet, run your algorithm, and add the results to a temporary list tmp. Once the list is ready, grab its iterator, and use it for subsequent invocations.

Categories

Resources