How to make n nested for loops recursively? - java

I have a method that must do the following:
for (int a01 = 1; a01 <= 25; a01++) {
for (int a02 = a01 + 1; a02 <= 25; a02++) {
for (int a03 = a02 + 1; a03 <= 25; a03++) {
...
System.out.println(a01 + "," + a02 + "," + ... + "," + a015);
}
}
}
I'd like to specify the number of nested for's (in the case above, I want 15 nested for's).
Is there a way to use recursive programming here?

Yes. This can be performed by recursive programming.
I assume you do not like to WRITE DOWN these nested for's in source code - as in your example, because this is really ugly programming - like the commentors explain.
The following (pseudo Java-like) code illustrates it. I assume a fixed depth for the nesting. Then you actually like to loop over an integer vector of dimension depth.
int[] length = new int[depth];
int[] counters = new int[depth];
The array counters has to be initialised to 0 (Arrays.fill(counters,0)). The array length has to be initialised to the number of iterations for the respective for loop.
I assume that you like to perform a certain operation within the inner loop. I will call this
performOperation(int[] counters);
- it depends on the multi-dimensional counter, i.e. the counters of the outer for's.
Then you can run the nested for loops by calling
nestedLoopOperation(counters, length, 0);
where
void nestedLoopOperation(int[] counters, int[] length, int level) {
if(level == counters.length) performOperation(counters);
else {
for (counters[level] = 0; counters[level] < length[level]; counters[level]++) {
nestedLoopOperation(counters, length, level + 1);
}
}
}
In your case your System.out.println() would be
performOperation(int[] counters) {
String counterAsString = "";
for (int level = 0; level < counters.length; level++) {
counterAsString = counterAsString + counters[level];
if (level < counters.length - 1) counterAsString = counterAsString + ",";
}
System.out.println(counterAsString);
}

I created this program to show all the different possible combination of cards (non repeating). It uses recursive for loops. Maybe it can help you.
//I'm lazy, so yeah, I made this import...
import static java.lang.System.out;
class ListCombinations {
//Array containing the values of the cards
static Symbol[] cardValues = Symbol.values();
//Array to represent the positions of the cards,
//they will hold different card values as the program executes
static Symbol[] positions = new Symbol[cardValues.length];
//A simple counter to show the number of combinations
static int counter = 1;
/*Names of cards to combine, add as many as you want, but be careful, we're
talking about factorials here, so 4 cards = 24 different combinations (4! = 24),
but 8 cards = 40320 combinations and 13 cards = 6.23 billion combinations!*/
enum Symbol {
AofSpades, TwoofSpades, ThreeofSpades, FourofSpades
}
public static void main(String args[]) {
//I send an argument of 0 because that is the first location which
//we want to add value to. Every recursive call will then add +1 to the argument.
combinations(0);
}
static void combinations(int locNumber) {
/* I use a recursive (repeating itself) method, since nesting for loops inside
* each other looks nasty and also requires one to know how many cards we will
* combine. I used 4 cards so we could nest 4 for loops one after another, but
* as I said, that's nasty programming. And if you add more cards, you would
* need to nest more for loops. Using a recursive method looks better, and gives
* you the freedom to combine as many cards as you want without changing code. */
//Recursive for loop nesting to iterate through all possible card combinations
for(int valueNumber = 0; valueNumber < cardValues.length; valueNumber++) {
positions[locNumber] = cardValues[valueNumber];
if (locNumber < (cardValues.length-1)) {
combinations(locNumber + 1);
}
//This if statement grabs and displays card combinations in which no card value
// is repeated in the current "positions" array. Since in a single deck,
// there are no repeated cards. It also appends the combination count at the end.
if (locNumber == (cardValues.length-1) && repeatedCards(positions)) {
for (int i = 0; i < cardValues.length; i++) {
out.print(positions[i]);
out.print(" ");
}
out.printf("%s", counter);
counter++;
out.println();
}
}
}
static boolean repeatedCards(Symbol[] cards) {
/*Method used to check if any cards are repeated in the current "positions" array*/
boolean booleanValue = true;
for(int i = 0; i < cardValues.length; i++) {
for(int j = 0; j < cardValues.length; j++) {
if(i != j && cards[i] == cards[j]) {
booleanValue = false;
}
}
}
return booleanValue;
}
}

Related

How to sort number when entering vector in java

I want to add numbers in sorted way before entering vector. But the result is not right and I am confused where the problem is ? Output is shown below.
I want to sort using some algorithm without any inbuilt methods.
import java.util.Vector;
public class Test {
public static void main(String ar[]){
//Numbers to enter in vector
int[] number = {5,2,98,3,10,1};
Vector<Integer> v = new Vector<Integer>();
v.add(number[0]);
for(int i=1;i<number.length;i++){
for(int j=v.size();j>0;j--){
System.out.println("Entered: "+number[i]);
if(number[i] <= v.get(j-1)){
v.add(j-1,number[i]);
break;
}else{
v.add(j,number[i]);
break;
}
}
}
for(int s:v)
System.out.print(s + " ");
}
}
OUTPUT:
Entered: 2
Entered: 98
Entered: 3
Entered: 10
Entered: 1
2 5 3 10 1 98
You have a second (inner) for loop based on the variable j, but that "loop" will only execute exactly one time. Both conditions inside the j loop cause the loop to exit (break;).
When you're adding each number, the only possibilities are last or next to last.
Your inner for loop doesn't actually loop.
Regardless of the condition number[i] <= v.get(j-1),
the loop will exit after one step.
What you want to do is,
iterate from the beginning of the vector,
and when you find an element that's bigger than the one you want to insert,
then insert it, and break out of the loop.
This is opposite of what you did so far, which is iterating from the end of the vector.
If the end of the loop is reached without inserting anything,
then append the value.
The program badly needs some other improvements too:
If you don't need the vector to be thread-safe, then you don't need Vector. Use ArrayList instead.
The special treatment for the first number is unnecessary.
The outer loop can be written in a more natural way using the for-each idiom.
No need to loop to print the elements, the toString implementation of Vector is already easy to read.
The variable names are very poor and can be easily improved.
The indentation is inconsistent, making the code very hard to read.
With the problem fixed and the suggestions applied:
List<Integer> list = new ArrayList<>();
for (int current : numbers) {
boolean inserted = false;
for (int j = 0; j < list.size(); j++) {
if (current <= list.get(j)) {
list.add(j, current);
inserted = true;
break;
}
}
if (!inserted) {
list.add(current);
}
}
System.out.println(list);
Last but not least, instead of searching for the insertion point by iterating over the list,
you could achieve much better performance using binary search,
especially for larger sets of values.
Another simple solution would be:
import java.util.Vector;
public class Test {
public static void main(String ar[]){
//Numbers to enter in vector
int[] number = {5,2,98,3,10,1};
Vector<Integer> v = new Vector<Integer>();
v.add(number[0]);
for(int i=1, j;i<number.length;i++){ //j declared here for better scope
for(j=v.size();j>0 && v.get(j-1)>number[i] ;j--); //<-- some changes here,
v.add(j,number[i]); //<-- and here
}
}
for(int s:v)
System.out.print(s + " ");
}
}
The inner for loop is simply used to find the right index for an element to be inserted.
Your inner loop seems to not looping more than one time. That's why the key is not being inserted into right place.
A more concise solution would be
public class Test {
public static void main(String ar[]){
//Numbers to enter in vector
int[] number = {5,2,98,3,10,1};
Vector<Integer> v = new Vector<Integer>();
v.setSize(number.length);
v[0] = number[0];
for(int i=1, vSize = 1; i < number.length; i++, vSize++){
int j = 0, k = 0;
for(j = 0; j < vSize; j++) {
if(v[j] < number[i]) {
break;
}
for(k = vSize; k > j; k--) {
v[k] = v[k -1];
}
v[k] = number[i];
}
for(int s:v)
System.out.print(s + " ");
}
}

How to randomly combine elements of 2 arrays while making sure to not reuse an element until all have been used at least once?

Essentially I'm writing a program that produces random poems out of an array of nouns and an array of adjectives.
This is accomplished basically using this line
String poem = adjectives[rand.nextInt(3)]+" "+ nouns[rand.nextInt(3)];
Simple enough, but I'm supposed to make sure that it doesn't reuse the same noun or adjective for the next poems until all of them have been used at least once already. I'm not sure how to do that.
Convert the arrays to list, so you can use Collections.shuffle to shuffle them. Once shuffled, you can then simply iterate over them. The values will be random order, and all words will be used exactly once. When you reach the end of an array of words, sort it again, and start from the beginning.
If a poem consists of 1 adjective + 1 noun as in your example, then the program could go something like this:
List<String> adjectives = new ArrayList<>(Arrays.asList(adjectivesArr));
List<String> nouns = new ArrayList<>(Arrays.asList(nounsArr));
Collections.shuffle(adjectives);
Collections.shuffle(nouns);
int aindex = 0;
int nindex = 0;
for (int i = 0; i < 100; ++i) {
String poem = adjectives.get(aindex++) + " " + nouns.get(nindex++);
System.out.println(poem);
if (aindex == adjectives.size()) {
aindex = 0;
Collections.shuffle(adjectives);
}
if (nindex == nouns.size()) {
nindex = 0;
Collections.shuffle(nouns);
}
}
The program will work with other number of adjectives and nouns per poem too.
If you must use an array, you can implement your own shuffle method, for example using the Fisher-Yates shuffle algorithm:
private void shuffle(String[] strings) {
Random random = new Random();
for (int i = strings.length - 1; i > 0; i--) {
int index = random.nextInt(i + 1);
String temp = strings[i];
strings[i] = strings[index];
strings[index] = temp;
}
}
And then rewrite with arrays in terms of this helper shuffle function:
shuffle(adjectives);
shuffle(nouns);
int aindex = 0;
int nindex = 0;
for (int i = 0; i < 100; ++i) {
String poem = adjectives[aindex++] + " " + nouns[nindex++];
System.out.println(poem);
if (aindex == adjectives.length) {
aindex = 0;
shuffle(adjectives);
}
if (nindex == nouns.length) {
nindex = 0;
shuffle(nouns);
}
}
What you can do is make two more arrays, filled with boolean values, that correspond to the adjective and noun arrays. You can do something like this
boolean adjectiveUsed = new boolean[adjective.length];
boolean nounUsed = new boolean[noun.length];
int adjIndex, nounIndex;
By default all of the elements are initialized to false. You can then do this
adjIndex = rand.nextInt(3);
nounIndex = rand.nextInt(3);
while (adjectiveUsed[adjIndex])
adjIndex = rand.nextInt(3);
while (nounUsed[nounIndex]);
nounIndex = rand.nextInt(3);
Note, once all of the elements have been used, you must reset the boolean arrays to be filled with false again otherwise the while loops will run forever.
There are lots of good options for this. One is to just have a list of the words in random order that get used one by one and are then refreshed when empty.
private List<String> shuffledNouns = Collections.EMPTY_LIST;
private String getNoun() {
assert nouns.length > 0;
if (shuffledNouns.isEmpty()) {
shuffledNouns = new ArrayList<>(Arrays.asList(nouns));
Collections.shuffle(wordOrder);
}
return shuffledNouns.remove(0);
}
Best way to do this is to create a shuffled queue from each array, and then just start popping off the front of the queues to build your poems. Once the queues are empty you just generate new shuffled queues and start over. Here's a good shuffling algorithm:
https://en.wikipedia.org/wiki/Fisher–Yates_shuffle
How about keeping two lists for the adjectives and nouns? You can use Collections.shuffle() to order them randomly.
import java.util.*;
class PoemGen {
static List<String> nouns = Arrays.asList("ball", "foobar", "dog");
static List<String> adjectives = Arrays.asList("slippery", "undulating", "crunchy");
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
System.out.println(String.format("\nPoem %d", i));
generatePoem();
}
}
private static void generatePoem() {
Collections.shuffle(nouns);
Collections.shuffle(adjectives);
int nounIndex = nouns.size() - 1;
int adjectiveIndex = adjectives.size() - 1;
while (nounIndex >= 0 && adjectiveIndex >= 0) {
final String poem = adjectives.get(adjectiveIndex--)+" "+ nouns.get(nounIndex--);
System.out.println(poem);
}
}
}
Output:
Poem 0
crunchy dog
slippery ball
undulating foobar
Poem 1
undulating dog
crunchy ball
slippery foobar
Poem 2
slippery ball
crunchy dog
undulating foobar
Assuming you have the same number of noums and adjectives shuffle both arrays and then merge result. you can shuffle the arrays multiple times if you need (once you get to the end)
shuffleArray(adjectives);
shuffleArray(nouns);
for(int i=0;i<3;i++) {
String poem = adjectives[i] + " " + nouns[i];
}
A simple method to shuffle the arrays:
static void shuffleArray( String[] data) {
for (int i = data.length - 1; i > 0; i--) {
int index = rnd.nextInt(i + 1);
int aux = data[index];
data[index] = data[i];
data[i] = aux;
}
}
This might be overkill for this specific problem but it's an interesting alternative in my opinion:
You can use a linear congruential generator (LCG) to generate the random numbers instead of using rand.nextInt(3). An LCG gives you a pseudo-random sequence of numbers using this simple formula
nextNumber = (a * x + b) % m
Now comes the interesting part (which makes this work for your problem):
The Hull-Dobell-Theorem states that if your parameters a, b and m fit the following set of rules, the generator will generate every number between 0 and m-1 exactly once before repeating.
The conditions are:
m and the offset c are relatively prime
a - 1 is divisible by all prime factors of m
a - 1 is divisible by 4 if m is divisible by 4
This way you could generate your poems with exactly the same line of code as you currently have but instead just generate the array index with the LCG instead of rand.nextInt. This also means that this solution will give you the best performance, since there is no sorting, shuffling or searching involved.
Thanks for the responses everyone! This helped immeasurably. I am now officially traumatized by the sheer number of ways there are to solve even a simple problem.

Array with loops Java

I want to print put the elements in an array that only occur twice. So if, for example, number 2 occurs 3 or 4 times, it should not be printed. The code I've written so far is below.
The issue in my code is with the loop. For example, for the number 2, since j=i+1 is the initialization condition, the inner loop won't read the elements before the jth location- since there is a 2 at index 6, it won't count the 2s before it, making the required condition true and displaying the 2. Is there a way to fix this?
public class Problem2 {
public static void exactlytwice(int[] x) {
int count, j;
for (int i = 0; i < x.length; i++) {
count = 0;
for (j = i + 1; j < x.length; j++) {
if (x[i] == x[j])
count++;
}
if (count == 1) System.out.print(x[i] + " ");
}
}
public static void main(String[] args) {
int[] x = new int[15];
x[0] = 2;
x[1] = 2;
x[2] = 2;
x[3] = 13;
x[4] = 44;
x[5] = 44;
x[6] = 2;
x[7] = 63;
x[8] = 63;
x[9] = 90;
x[10] = 1;
x[11] = 2;
x[12] = 150;
x[13] = 150;
x[14] = 180;
exactlytwice(x);
}
}
aside from the issue you wrote, the bigger problem I see with your code is that its inefficient. You are doing a loop inside a loop here, which is very slow (o(n^2)).
My suggestion is to keep a map of numbers->count, and then only take the ones that appear only twice in the map:
public static void exactlytwice(int[] x) {
Map<Integer, Integer> counter = new HashMap<>();
for (int i = 0; i < x.length; i++) {
if (counter.contains(i)) {
counter.put(i,1);
} else {
counter.put(i,counter.get(i)+1);
}
}
for (Integer i : counter.keyset()) {
if (counter.get(i) == 2) {
System.out.println(i);
}
}
}
Think about maintaining a seperate array/list which keeps track of all the elements that has been counted/printed by which you could just skip the same number that shows again down the array.
Or you could sort the array and then perform the whole logic to check for duplicates.
Just for completeness, there is a solution without extra-map. It's still O(n^2), but uses no extra memory. And It uses kind of fun idea.
First, we only need to output first occurence of a number, every other one is not relevant, because we either have more than 2 of them, or we've already output the first one.
Second, we can then indeed continue, from i+1 element, because at this point, there are no elements equal to ith, that are earlier in array.
public static void exactlytwice(int[] x) {
int count, j;
TOP:
for (int i = 0; i < x.length; i++) {
count = 0;
for (j = 0; j < i; j++) {
if (x[j] == x[i])
// had this number earlier, so go to the next one.
continue TOP;
}
for (j = i+1; j < x.length; j++) {
if (i != j && x[i] == x[j])
count++;
}
if (count == 1) System.out.print(x[i] + " ");
}
}
In addition to the answers provided, there are two more ways you could go about this:
If array modification is permitted, change elements already encountered to a dummy value, and skip the value if encountered. This reduces the time complexity to O(n) from O(n^2), but destroys the original array. Of course, this assumes that the acceptable integers are restricted to a certain set (thanks to #Dzmitry Paulenka for reminding me that I hadn't stated this explicitly). To keep the array, you could make a copy (although then the space complexity becomes O(n) ).
If any integer is acceptable, then create an encountered boolean array, all intialized to false. Change the locations of elements encountered in the original array to true in the encountered boolean array, and if the value is already true, it can be skipped. Again, time complexity O(n), but O(n) space complexity, and unlike in the second method of 1., does not require the permissible range of numbers (ints) to be restricted.
Alternately, simply make the initialization of j as j=0, and then ensure that only those numbers which don't have that number appearing before them are printed, i.e., that the number is printed only if it occurs at j>=i (thanks to #Nir Levy for pointing the j>=i requirement out). This is (slightly) more inefficient than the code already written, but the time complexity remains the same O(n^2).
With Java 8 you can achieve this using streams like this :
public static void main(String[] args)
{
List<Integer> list = Stream.of(12,1,3,4,2,3,7,6,7,3,1,8,4,12,33,45,78,36,8)
.collect(Collectors.groupingBy(x->x, Collectors.summingInt(x->1)))
.entrySet().stream().filter(x->x.getValue()==2)
.collect(ArrayList<Integer>::new,(x,y)->x.add(y.getKey()),ArrayList<Integer>::addAll);
System.out.println(list);
}
The result is :
[1, 4, 7, 8, 12]
Code:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
public class Writer {
private int counter;
private Random generator = new Random();
private List<Integer> data = new ArrayList<Integer>();
private Map<Integer,Integer> map = new HashMap<Integer,Integer>();
public Writer(int n){
populate(n);
}
private final void populate(int n){
for(int i = 0; i != n; i++){
data.add(generator.nextInt(10));
}
}
private final void reset(){
this.counter = 0;
}
public final void occurence(){
for(int dp : data){
for(int i = 0; i < data.size(); i++){
if(dp == data.get(i)){
counter += 1;
}
}
map.put(dp, counter);
reset();
}
}
public final void filter(int d){
for(int key : map.keySet()){
if(map.get(key) == d){
System.out.println("Key: " + key + " Value: " + map.get(key));
}
}
}
public void rawData(){
System.out.println(data.toString());
}
public void output(){
System.out.println(map.toString());
}
Initiate:
// Create instance of Writer class and generate '100' random numbers
Writer writer = new Writer(100);
// Output raw data
writer.rawData();
// Process data
writer.occurence();
// Filter numbers with occurence '10'
writer.filter(10);
// Output processed data
writer.output();
Output (from from calling filter(10)):
Key: 3 Value: 10
Key: 8 Value: 10

List of Non-Repeating Ints in Java? Assignment

I'm trying to create a list of 20 integers between 0 and 26 (so in the 1-25 range) that does not repeat as a part of an assignment. I thought I had it figured out, but the program keeps looping over and over without ever ending. Can anyone help me out?
import java.util.Random;
public class prog433a
{
public static void main(String args[])
{
Random r = new Random();
int[] list = new int[20];
for (int k = 0; k < list.length; k++)
{
boolean notADupe = false;
while (notADupe == false)
{
list[k] = r.nextInt(25) + 1;
for (int j = 0; j < list.length; j++)
{
if (list[j] == list [k] && j != k)
{
notADupe = true;
}
else
{
notADupe = false;
break;
}
}
System.out.println(list[k]);
}
}
}
}
EDIT: This is different from the other question because I am trying to figure out how to check for uniqueness using the methods that I am allowed to use in my assignment (essentially, the ones I'm already using in the code).
I think you've reversed the condition out there. Inside if, you should set notADup to false, rather than true. However, I would make the variable isDup instead, and change the while loop accordingly.
One more suggestion: instead of while (notADupe == false), you should just use while (!notADupe). Never compare boolean variables like that. It might surprise you at times.
So to solve your issue, just change your if-else block to:
if (list[j] == list [k] && j != k) {
notADupe = false;
break;
} else {
notADupe = true;
}
BTW, your solution is a bit complex. For every element, you are iterating over whole array to find duplicate. Rather I would suggest you to maintain a Set<Integer> storing the already seen numbers, and check in that every randomly generated number. If present, skip it and re-generate.
Pseudo code would look something like this:
arr = [] // Your list array, initialize to size 20
seen = [] // A Set
for i from 1 -> arr.length
num = rand.nextInt(25) + 1
while seen contains num
num = rand.nextInt(25) + 1
seen.add(num)
arr[i] = num

Dynamically change the number of nested for loops

I don't know if this is a stupid question, but I need to dynamically change the number of for-loops without using recursion.
For example, if n=3, I need 3 nested for-loops.
for(int i=0; i<size; i++){
for(int j=0; j<size-1; j++){
for(int k=0; k<size-2; k++){
//do something
}
}
}
If n=5:
for(int i=0; i<size; i++){
for(int j=0; j<size-1; j++){
for(int k=0; k<size-2; k++){
for(int l=0; l<size-3; l++){
for(int m=0; m<size-4; m++){
//do something
}
}
}
}
}
Is there any way to achieve this without recursion?
Another question: what is the use of Multiple Dispatch in Java? I'm trying to code something in ONE METHOD, and it should run different events in different cases of the parameter. NO IF STATEMENTS / TERNARY OPERATORS / CASES.
NOTE: I can ONLY have one method (part of the problem), and cannot use recursion. Sorry.
Think about how many times you run through this loop. It looks like (size!) / (size - n)!:
int numLoops = 1;
for (int i = 0; i < n; i++) {
numLoops*= (size - i);
}
for (int i = 0; i < numLoops; i++) {
//do something
}
It depends what exactly you're trying to do. Recursion can always be replaced with iteration (see this post for examples using a Stack to store state).
But perhaps the modulo (%) operator could work here? i.e. Have a single loop that increments a variable (i) and then the other variables are calculated using modulo (i % 3 etc). You could use a Map to store the values of the variables indirectly, if there are a varying number of variables.
You have to create array of loop counters and increment it manually.
Quick and dirty example:
public static void nestedFors(int n, int size) {
assert n > size;
assert size > 0;
int[] i = new int[n];
int l = n - 1;
while(l >= 0) {
if(l == n - 1) {
System.out.println(Arrays.toString(i));
}
i[l]++;
if(i[l] == size - l) {
i[l] = 0;
l--;
} else if(l < n - 1) {
l++;
}
}
}
Replace System.out.println(Arrays.toString(i)) with your own code.
You can check it here: http://ideone.com/IKbDUV
It's a bit convoluted, but: here is a way to do it without recursion, in one function and without ifs.
public static void no_ifs_no_recursion(int n){
int[] helper = new int[n-1];
int[] pointers = new int[n]; //helper for printing the results
int totalsize = 1;
for (int loops = 2; loops <= n; loops++){
helper[n - loops] = totalsize;
totalsize*=loops;
}
for (int i=0; i<totalsize; i++){
int carry = i;
for (int loops = 0; loops < n-1; loops++){
pointers[loops] = carry/helper[loops];
carry = carry - (pointers[loops]*helper[loops]);
}
System.out.println(Arrays.toString(pointers));
//or do something else with `i` -> `pointers[0]`, `j` -> `pointers[1]`, `k` -> `pointers[2]` etc..
}
}
I think you need a backtracking algorithm.
But then you would replace your nested loops with recursion.
I don't want to post links here as seems moderators don't like that.
Look at "eight queens puzzle" (you can Google it), you will get my idea.
I know this idea works as I've posed this same question (which you have) to myself on many occasions, and I've applied it several times successfully.
Here is a small example (I changed it as the previous one was a bit complex).
public class Test001 {
public static void main(String[] args) {
loop(0, 5, 10);
}
/**
* max_level - the max count of nesting loops
* size - the size of the collection
*
* 0 - top most level
* level 1 - nested into 0
* level 2 - nested into 1
* ...
* and so on.
*/
private static void loop(int level, int max_level, int size){
if (level > max_level) return;
for (int i=0; i<size-level; i++){
System.out.println("Now at level: " + level + " counter = " + i);
loop(level + 1, max_level, size);
}
}
}
But this still uses recursion.

Categories

Resources