Dynamically change the number of nested for loops - java

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.

Related

Ordering a list of 10 numbers

I have an atomic integer array of size 10. I am using this array to organize numbers 1-10 sent in by threads. This 1-10 will eventually be able to change to be a range of numbers larger than 10 and the list is to contain the 10 greatest numbers in that range. I can see the numbers going into the loops and recognizing that they are greater than a number currently there. However, there is never more than 2 numbers in the array when it is printed out. I have tried to trace my code in debug mode, however, it looks as if it is working as intended to me. I feel like there may be a simple error to my logic? I am completely sure all values are entering in the function as I have triple checked this. I start at the end of the array which should contain the highest value and then swap downwards once the slot has been determined. I would appreciate the assistance. This is just a simple experiment I am doing in order to grasp the basics before I try to tackle a homework assignment.
Here an example of my code:
public class testing{
static AtomicIntegerArray maxList = new AtomicIntegerArray(10);
final static int n = 10;
static void setMax(int value)
{
for(int i = 9; i >= 0; i--)
{
if(value > maxList.get(i))
{
int temp = maxList.get(i);
maxList.set(i,value);
if(i == 0)
{
maxList.set(i, value);
}
else
{ for(int j = i-1; j > 0; j--)
{
maxList.set(j, temp);
temp = maxList.get(j-1);
}
}
break;
}
}
public static void main(String[] args)
{
for (int i = 0; i < n; i++)
{
setMax(i);
}
}
}
Here is an example of how it is being called:
Brooke, there is a small bug in your 'j' loop. You had saved the state of a variable (temp), however your logic in the j loop lost the state. This new logic preserves the state of the previous element in the list.
Try this:
for (int j = i - 1; j >= 0; j--) {
int t2 = maxList.get(j);
maxList.set(j, temp);
temp = t2;
}

Calculating the factorial of every element in an integer array

I need to create a Method that has 2 parameters in Java, upperborder and lowerborder. This method must create an array from the number 2 to the number 10.
Then I must implement another method, that calculates the factorial for a given number.
Then I must implement a third method that calculates the factorial for every element in the created array and test all these methods in a TestClass.
I know how to do this, but apparently I'm making some kind of a mistake in my code and it gives me the StackOverflow exception. I read the code a couple of times, but I can't seem to quite understand where I'm wrong.
package fakultaetinarray;
public final class FakultaetinArray{
private int i;
private int[] a;
private int j;
public FakultaetinArray(){
System.out.println("Given array : ");
createArray(1, 9);
System.out.println("Factorial for every element : ");
FakinArray();
}
public int fakRe(int n){
if(n == 1){
return n;
}
return n * fakRe(n - 1);
}
public void createArray(int untergrenze, int obergrenze){
this.a = new int[obergrenze];
for(this.j = 1; j <= a.length; j++){
a[i] = j + 1;
System.out.println(a[i]);
}
}
public void FakinArray(){
a[0] = 2;
for(i = 1; i < a.length; i++){
int fak = fakRe(a[i]);
a[i] = fak;
System.out.println(fak);
}
}
}
The reason you're getting StackOverflowErrors is due to your recursive method not having a case when n == 0.
The reason that your values are coming in as 0 is due to how you're constructing your loop.
for(this.j = 1; j <= a.length; j++){
a[i] = j + 1;
System.out.println(a[i]);
}
It's unclear why you're using j here at all, and i is initialized to its default value of 0, so in all reality, you're only ever filling one element of your array with a positive value and all of the others are at zero.
You need to reconsider how your loops are constructed. I would strongly encourage you not to make them fields, but declare them as part of the loop construct instead.
if(n == 1){ is not a strong enough condition to block the recursion: n can go below 1. In your particular case, you have a situation where n is 0.
Consider unwinding the recursion to a simple loop in any case. As a rule of thumb, recursion is not good for O(N) stuff.

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

set even to 0 and odd to 1

I'm playing around with double arrays and am trying to set all the even elements of an array to 0 and all of the odd elements of the array to 1. Everything looks okay to me, but when I run it I get a bunch of errors. Not sure what's wrong; I've been looking at it for a while with no luck. Any advice on how to fix the errors it gives would be great, thanks!
Code:
public class SetOf0and1 {
public static void main(String[]args)
{
int [][] numbers1 = {{4,2,5}, {2,4,1}, {1,3}};
System.out.println("Before setting elements between 0 and 1: ");
displayArray(numbers1);
setEvenRowsTo0OddRowsTo1 (numbers1);
System.out.println("After setting the elements between 0 and 1");
displayArray(numbers1);
}
public static void setEvenRowsTo0OddRowsTo1(int [][]array)
{
for(int i=0; i<array.length;i++)
{
for(int j=0; j<array[i].length;j++)
{
if(i%2 == 0)
array[i][j]=0;
else
array[i][j]=1;
}
}
}
public static void displayArray(int [][]array)
{
for(int i=0;i<array.length;i++)
{
for( int j=0; j<array.length;j++)
{
System.out.println(array[i][j] + " " );
}
System.out.println();
}
}
}
Errors given:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
at SetOf0and1.displayArray(SetOf0and1.java:38)
at SetOf0and1.main(SetOf0and1.java:10)
public static void displayArray(int [][]array)
{
for(int i=0;i<array.length;i++)
{
for( int j=0; j<array.length;j++)
^^^^^^^^^
{
System.out.println(array[i][j] + " " );
}
System.out.println();
}
Your inner loop should stop at array[i].length.
In the method displayArray, the line:
for( int j=0; j<array.length;j++)
Should be:
for( int j=0; j<array[i].length;j++)
array.length does not return the length you thing it does! You have a 2 dimentional array. So if we say you have array[x][y] then array.length will be x and array[i].length (for 0 <= i < x) will be y. This could be different depending on the length of the array on that index. (so the formula does not exactly apply like that)
int [][] numbers1 = {{4,2,5}, {2,4,1}, {1,3}};
this statement initializes an array with three arrays of the legthes 3, 3 and 2!!!
(in the third block you have only two elements !!! - {1,3})
In your displayArray-method you use two times ...
array.length
... to distinct the size of the loop
that sets the number of loops to 3 ... But last block is only two elements long -> errror.
Use this instead for the second loop:
for( int j=0; j<array[i].length;j++)
If you want to check if a number is odd, you can do it this way:
int answer = thenumber % 2;
'thenumber' is the integer to check if it is even.
Then 'answer' would be 0 if the number was even.
And if you want to loop through the array and do it:
for (int i = 0; i < numbers1.length(); i++)
{
if (numbers1[i] % 2 == 0) {
//EVEN
numbers1[i] = 0;
}
else if (numbers1[i] % 2 == 1) {
//ODD
numbers1[i] = 1;
}
}
And, even more compact:
for (int i = 0; i < numbers1.length(); i++)
{
numbers1[i] %= 2;
}
Edit: I forgot that it was an array you had! I was thinking about ArrayList! Fixed.

How to make n nested for loops recursively?

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;
}
}

Categories

Resources