two dimensional array with links and linkweights in java - java

I am working on a page ranking case study where the input is firstly the number of nodes, followed by the links for each page i to page j. The entire input has to be split according to lines and spaces (since the input is one big string consisting of multiple lines with integers). The tests I want to implement are: getNodeSize which simply returns the node, hasLink(integer i, integer j) of boolean whether or not (resp., true or false) there is a link from node i to node j (counting from 0 to nodes-1 ), and a method linkWeight(integer i, integer j) that returns the number of links between integer i and j. (after that there are some other methods but I will figure those out later)
My code so far is:
public class WebGraph {
static Scanner s = new Scanner(System.in);
static int nodes = s.nextInt();
double wg [][]= new double [nodes][nodes];
static ArrayList<String> array = new ArrayList<String>();
static int[][] counts = new int[nodes][nodes];
static int[] outDegree = new int[nodes];
public static WebGraph initFromScanner(Scanner s) {
do{
for(int i = 0; i<nodes-1; i++){
}
String[] strArray = s.nextLine().split("\\s+");
int[] intArray = new int[strArray.length];
for(int i = 0; i < strArray.length; i++) {
intArray[i] = Integer.parseInt(strArray[i]);
}
}while(s.hasNext());
return null;
}
public Object getNodeSize() {
nodes = s.nextInt();
return nodes;
}
public boolean hasLink(int i, int j) {
for (int h = 0; h<wg[i].length; h++) {
if(h==j){
return true;
}
}
return false;
}
public void linkWeight(int a, int b) {
while (s.hasNext()) {
int i = s.nextInt();
int j = s.nextInt();
outDegree[i]++;
counts[i][j]++;
}
}
public List<Integer> successorsSortedList(int i) {
// TODO Auto-generated method stub
return null;
}
public int[][] asMatrix() {
return null;
}
public Set<Integer> successorsSortedSet(int i) {
return null;
}
}
for the testcase:
public class I5Exc4aTest {
WebGraph wg;
/**
* This will be invoked before each testcase.
* Ensure to copy/paste the content of file
* 'ext/web1.txt' to the Eclipse console.
* In L6, we will teach you how to automate that!
* #throws Exception
*/
#Before
public void setUp() throws Exception {
Scanner s = new Scanner(System.in);
System.out.println("Please copy/paste the content of "
+ "file 'ext/web1.txt' to this console. "
+ "Then, press ENTER.");
wg = WebGraph.initFromScanner(s);
}
#Test
public void testGetNodeSize() {
assertEquals(50, wg.getNodeSize());
}
#Test
public void testHasLink1() {
assertFalse(wg.hasLink(0, 0));
}
#Test
public void testHasLink2() {
assertTrue(wg.hasLink(0, 7));
}
#Test
public void testLinkWeight1() {
assertEquals(1, wg.linkWeight(0, 7));
}
#Test
public void testLinkWeight2() {
assertEquals(1, wg.linkWeight(0, 34));
}
#Test
public void testLinkWeight3() {
assertEquals(2, wg.linkWeight(1, 22));
}
#Test
public void testSuccessorsSortedList() {
List<Integer> a = wg.successorsSortedList(1);
List<Integer> expected = Arrays.asList(new Integer(14),
new Integer(22), new Integer(22), new Integer(45));
assertTrue("Expected 'a' and 'expected' to be equal."+
"\n 'a' = "+a+
"\n 'expected' = "+expected,
expected.equals(a));
}
#Test
public void testSuccessorsSortedSet() {
Set<Integer> a = wg.successorsSortedSet(1);
Set<Integer> expected = new java.util.TreeSet<Integer>(
Arrays.asList(new Integer(14), new Integer(22), new Integer(45)));
assertTrue("Expected 'a' and 'expected' to be equal."+
"\n 'a' = "+a+
"\n 'expected' = "+expected,
expected.equals(a));
}
#Test
public void testAsMatrix1() {
int[][] copy= wg.asMatrix();
assertArrayEquals(new int[]{0, 1, 0, 1, 0, 0}, copy[0]);
assertArrayEquals(new int[]{1, 0, 1, 0, 0, 1}, copy[1]);
assertArrayEquals(new int[]{0, 1, 2, 0, 1, 0}, copy[2]);
assertArrayEquals(new int[]{1, 2, 0, 1, 0, 0}, copy[3]);
assertArrayEquals(new int[]{1, 1, 0, 0, 0, 1}, copy[4]);
assertArrayEquals(new int[]{0, 1, 0, 2, 0, 0}, copy[5]);
}
}
Any help on any of the methods would be greatly appreciated since now none of my test cases work.
EDIT:
I am sorry for the unclear parts, this is the complete assignment:
"1.Provide a class WebGraph with an attribute w, and a method initFromScanner(Scanner s) that initializes itself by reading from the command line, based on the following format:
(a) The first input value is of type integer and represents the number of
nodes in the graph. In the following, we call the value of that integer N,
(b) The next N lines always start by an integer i representing a source
node's ID and then a (potentially empty) sequence of integers j that
denote links from node i to node j.
An example corresponding to this structure is listed below. This
example encompasses 5 nodes, where there a link from node 0 to
node 1, a link from node 0 to node 2, but no link from node 0 to
itself nor to nodes 3 or 4.
5
0 1 2
1 1 2 3
2 2 2 2 3 1
3
4 3 0 0
Provide a method getNodeSize that returns the value of N,
Provide a method hasLink(integer i, integer j) of type boolean
that returns whether or not (resp., true or false) there is a link from
node i to node j (counting from 0 to N-1 ),
Provide a method linkWeight(integer i, integer j) of type integer
that returns the number of links from node i to node j (counting from 0
to N-1 ),
Provide a method successorsSortedSet(integer i) of type Set
which represents the set of successor nodes according to the outgoing links
of node i, ordered by node ID.
Provide a method successorsSortedList(integer i) of type List
which represents a sequence of successor nodes according to the outgoing
links of node i, ordered by node ID.
Provide a method asMatrix() of type integer[][] that returns the ma-
trix representation described above. Ensure that you do not allow updates to the internal data of your object!"

Related

A method that returns a new array by eliminating * * the duplicate values in the array

/** eleminateDuplicates returns a new array with duplicate values eliminated */
public static int[] eliminateDuplicates(int[] list) {
int[] distinctList = new int[list.length];
int i = 0; // index distinctList
for (int e: list) {
if (linearSearch(distinctList, e) == -1) {
distinctList[i] = e;
i++;
}
}
return distinctList;
}
/** linearSearch */
public static int linearSearch(int[] array, int key) {
for (int i = 0; i < array.length; i++) {
if (key == array[i])
return i;
}
return -1;
}
For example if i insert 10 numbers 9,9,9..., and print it, the result is only 9.
I cant understand the logic of these methods. When u return i from linearSearch method, does it break from the loop?
Can u explain me step by step how the logic of these methods works!
Maybe this will help you understanding the flow, but I strongly recommend to learn to use a debugger, it will help you debug and understand the code.
import java.util.Arrays;
class Main {
public static void main(String[] args) {
eliminateDuplicates(new int[]{1, 2, 1, 2, 3, 3});
}
public static int[] eliminateDuplicates(int[] list) {
int[] distinctList = new int[list.length];
int i = 0;
// Iterate through each array elements
for (int e : list) {
// Verify if the value already exist. If the number exist return the index of the first apparition, otherwise -1.
if (linearSearch(distinctList, e) == -1) {
// Put the value to the distinctList is unique
distinctList[i] = e;
// Move to the next position in the distinctList array
i++;
System.out.printf("Element %d is not in the distinct array, so it will be added %s\n", e, Arrays.toString(distinctList));
} else {
System.out.printf("Element %d already in the distinct array, so it will be skipped\n", e);
}
}
// Return the distinctList that contain only unique values
return distinctList;
}
public static int linearSearch(int[] array, int key) {
// Iterate through each array elements
for (int i = 0; i < array.length; i++) {
// Check the current value of the array (array[i]) if it is the same with the given one return the current index
if (key == array[i])
// Same value, no need to search any more, so return from the method with the index of the value
return i;
}
// If the value was not found (the above condition "key == array[i]" was never true)
return -1;
}
}
Output
Element 1 is not in the distinct array, so it will be added [1, 0, 0, 0, 0, 0]
Element 2 is not in the distinct array, so it will be added [1, 2, 0, 0, 0, 0]
Element 1 already in the distinct array, so it will be skipped
Element 2 already in the distinct array, so it will be skipped
Element 3 is not in the distinct array, so it will be added [1, 2, 3, 0, 0, 0]
Element 3 already in the distinct array, so it will be skipped

Moving data in an array to the left

I'm really new to Java and there's something wrong with the code. No errors were detected, but the output is odd.
The goal is to move the data in an array to the left. For example:
x = {1,2,3}
the new array should be {2,3,1}.
Now the code below only gives me {0,0,0}. It'd be nice if you point out the mistake and tell me what to do. Thanks a lot beforehand!
public class Project1 {
public static int[] shiftone(int[]n,boolean left) {
n = new int[n.length];
int save,save2;
if(left = true){
save = n[0];
save2 = n[(n.length-1)];
for (int i = 1; i < n.length-1; i++) {
n[i-1]=n[i];
}
n[n.length-1] = save;
n[n.length-2] = save2;
}
else{
save = n[n.length-1];
for (int i=0;i<(n.length-1);i++)
n[(n.length)-i] = n[(n.length-1)-1];
n[0] = save;
}
return n;
}
public static void main(String[] args){
Scanner input = new Scanner(System.in);
int[] x;
int k;
boolean left;
System.out.print("Masukkan jumlah data yang ingin diinput: ");
k = input.nextInt();
System.out.println();
x = new int[k];
for (int i = 0; i < k; i++) {
System.out.print("Input data ke-"+i+": ");
x[i] = input.nextInt();
}
System.out.print("Array: "+Arrays.toString(x));
System.out.println();
System.out.print("Move to left? (true/false): ");
left = input.nextBoolean();
System.out.println();
int[] y;
y = new int[k];
y = shiftone(x,left);
System.out.print("New array: "+Arrays.toString(y));
}
}
As a simple solution for your goal, you can use this
public static int[] shiftone(int[] n, boolean left) {
// you don't need to shift anything if length = 1
if (n.length < 2) {
return n;
}
if (left) {
// save first element
int save = n[0];
for (int i = 1; i < n.length; i++) {
// shift from 1 to n
n[i-1] = n[i];
}
// insert saved element to array
n[n.length - 1] = save;
} else {
// the same
int save = n[n.length - 1];
for (int i = 1; i < n.length; i++)
n[n.length - i] = n[(n.length - 1) - i];
n[0] = save;
}
return n;
}
There is the very fast method to copy the array elements from one place to another. I don't know if this will be helpful to you since it seems to me your question is homework assignment. Nevertheless, I'll put the code with appropriate comments...
public class Answer {
public static void main(String[] args) {
//test case
int[] input = {1, 2, 3, 4, 5};
System.out.println(Arrays.toString(input));
//save the first element in the temporary variable
int temp = input[0];
//the fastest way to copy the array elements
//1st parameter is the source array
//2nd parameter is the source position (read: from which element to copy)
//3rd parameter is the destination (in this case the same array)
//4th parameter is the destination position (read: where to store the 1st element)
//5th parameter is the length of elements to copy (read: how many)
System.arraycopy(input, 1, input, 0, input.length - 1);
//finally store the saved element to the end
input[input.length - 1] = temp;
System.out.println(Arrays.toString(input));
}
}
If we don't want to code the moving on our own, we can use the method Collections.rotate . It takes a List and rotates the elements by a given distance. To use it, we need to convert the int array to a List<Integer>. The rotated list is converted back to an int array.
protected static int[] move(int[] input, int distance) {
List<Integer> inputList = Arrays.stream(input).boxed().collect(Collectors.toCollection(ArrayList::new));
Collections.rotate(inputList, distance);
return inputList.stream().mapToInt(Integer::intValue).toArray();
}
Usage:
public static void main(String[] args) throws Exception {
int[] input = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
int moveLeftOnce = -1;
int[] moved = move(input, moveLeftOnce); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
}
Please note:
Since Collections.rotate will move the elements in the given list, the list has to be modifiable. This is the case for an ArrayList. Therefore the code uses Collectors.toCollection(ArrayList::new) since there are (JavaDoc)
no guarantees on the type, mutability ... of the List returned
by Collectors.toList.

Function in java outputs different results when called multiple times

I have a function called tournamentTreeKSelection which finds the K-th largest element in an array. The function takes three parameters, the array, the same array again and the value of K. The purpose of sending two copies of the array is so that during recursive calls, I can modify one copy of the array and still keep the original array I sent in during that call. Here is the code:
import java.util.ArrayList;
import java.util.Arrays;
public class TournamentTree {
public static int max(int a, int b) {
return a > b ? a : b;
}
public static int[] toArray(ArrayList<Integer> list) {
int[] arr = new int[list.size()];
for(int i = 0; i < arr.length; ++i)
arr[i] = list.get(i);
return arr;
}
public static ArrayList<Integer> toList(int[] arr) {
ArrayList<Integer> list = new ArrayList<>();
for(int i : arr)
list.add(i);
return list;
}
public static int tournamentKSelection(int[] data, int[] data_copy, int k) {
ArrayList<Integer> winners = new ArrayList<>();
for(int i = 0; i < data.length; i += 2) {
winners.add(max(data[i], data[i + 1]));
}
if(k > 1 && winners.size() == 1) {
for(int i = 0; i < data_copy.length; i++)
if(data_copy[i] == winners.get(0))
data_copy[i] = -1;
return tournamentKSelection(data_copy, data_copy, --k);
}
if(winners.size() % 2 == 1 && winners.size() != 1) winners.add(-1);
if(winners.size() == 1) return winners.get(0);
return tournamentKSelection(toArray(winners), data_copy, k);
}
}
Now I am going to test it :
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[] arr = {9, 10, 8, 7, 6, 500, 4, 3, 2, 1};
System.out.println(TournamentTree.tournamentKSelection(arr,arr,1));
System.out.println(TournamentTree.tournamentKSelection(arr,arr,2));
System.out.println(TournamentTree.tournamentKSelection(arr,arr,3));
}
}
This produces the following results:
500 // ok this is the first largest number
10 // ok this is the second largest number
8 // this is the fourth largest number, not the third
Now let me make the call to System.out.println(TournamentTree.tournamentKSelection(arr,arr,3)); alone without the call to k = 1 and k = 2
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[] arr = {9, 10, 8, 7, 6, 500, 4, 3, 2, 1};
System.out.println(TournamentTree.tournamentKSelection(arr,arr,3));
}
}
Now this produces the correct result, which is 9. What's going on ? Individually, the result is correct but when I make previous calls to the same function first the subsequent results are wrong.
The only explanation I can think of at the moment is that something in my TournamentTree class is static that shouldn't be.
Any insight ?
I think you should call your function in this way:
System.out.println(TournamentTree.tournamentKSelection(arr.clone(), arr.clone(), 1));
And I recommend also interesting thread about arrays and passing them to function:
Are arrays passed by value or passed by reference in Java?
In the call TournamentTree.tournamentKSelection(arr,arr,3), you are passing in the same array for both args, so even though you are not changing the array through the second argument, you are changing it by the first. Java uses pass by reference, not pass by value. To maintain the original, you have to make a copy and pass in each, like:
public static void main(String[] args) {
int[] arr = {9, 10, 8, 7, 6, 500, 4, 3, 2, 1};
int[] arr_copy = java.util.Arrays.copyOf(arr, arr.length);
System.out.println(TournamentTree.tournamentKSelection(arr,arr_copy,3));
}

Passing a method with an array parameter to a driver/test file?

purpose of this program is to determine whether or not the variable value
is found within any block of an array (the size of this array is specified by
a user.)
All I want to do is call this method in a driver file and have the user input
the size/data in each block of the array and then enter a value that the program will look for in the array.
public class PracticeExamQ10
{
//method that recieves int array and int value//
public int search(int[] data, int value)
{
//for loop to search the entire array for value//
for(int i = 0; i < data.length; i++)
{
//if data is found, return the index number of value (spot in the array)//
if(data[i] == value)
return i;
}
//returns -1 if value does not occur in the array data//
return -1;
}
}
I then have this as my driver file;
public class PracticeExamQ10Test
{
public static void main(String[] args)
{
PracticeExamQ10 test = new PracticeExamQ10();
test.search({5, 4, 3, 2, 1}, 5);
}
}
is this even possible or do I have to do this instead?
public class PracticeExamQ10Test
{
public static void main(String[] args)
{
int[] data = {5, 4, 3, 2, 1};
PracticeExamQ10 test = new PracticeExamQ10();
test.search(data, 0);
}
}
test.search(new int[] { 5, 4, 3, 2, 1 }, 0);

Is there any way to do n-level nested loops in Java?

In other words, can I do something like
for() {
for {
for {
}
}
}
Except N times? In other words, when the method creating the loops is called, it is given some parameter N, and the method would then create N of these loops nested one in another?
Of course, the idea is that there should be an "easy" or "the usual" way of doing it. I already have an idea for a very complicated one.
jjnguy is right; recursion lets you dynamically create variable-depth nesting. However, you don't get access to data from the outer layers without a little more work. The "in-line-nested" case:
for (int i = lo; i < hi; ++i) {
for (int j = lo; j < hi; ++j) {
for (int k = lo; k < hi; ++k) {
// do something **using i, j, and k**
}
}
}
keeps the variables i, j, and k in scope for the innermost body to use.
Here's one quick hack to do that:
public class NestedFor {
public static interface IAction {
public void act(int[] indices);
}
private final int lo;
private final int hi;
private final IAction action;
public NestedFor(int lo, int hi, IAction action) {
this.lo = lo;
this.hi = hi;
this.action = action;
}
public void nFor (int depth) {
n_for (0, new int[0], depth);
}
private void n_for (int level, int[] indices, int maxLevel) {
if (level == maxLevel) {
action.act(indices);
} else {
int newLevel = level + 1;
int[] newIndices = new int[newLevel];
System.arraycopy(indices, 0, newIndices, 0, level);
newIndices[level] = lo;
while (newIndices[level] < hi) {
n_for(newLevel, newIndices, maxLevel);
++newIndices[level];
}
}
}
}
The IAction interface stipulates the role of a controlled action which takes an array of indices as the argument to its act method.
In this example, each instance of NestedFor is configured by the constructor with the iteration limits and the action to be performed by the innermost level. The parameter of the nFor method specifies how deeply to nest.
Here's a sample usage:
public static void main(String[] args) {
for (int i = 0; i < 4; ++i) {
final int depth = i;
System.out.println("Depth " + depth);
IAction testAction = new IAction() {
public void act(int[] indices) {
System.out.print("Hello from level " + depth + ":");
for (int i : indices) { System.out.print(" " + i); }
System.out.println();
}
};
NestedFor nf = new NestedFor(0, 3, testAction);
nf.nFor(depth);
}
}
and the (partial) output from its execution:
Depth 0
Hello from level 0:
Depth 1
Hello from level 1: 0
Hello from level 1: 1
Hello from level 1: 2
Depth 2
Hello from level 2: 0 0
Hello from level 2: 0 1
Hello from level 2: 0 2
Hello from level 2: 1 0
Hello from level 2: 1 1
Hello from level 2: 1 2
Hello from level 2: 2 0
Hello from level 2: 2 1
Hello from level 2: 2 2
Depth 3
Hello from level 3: 0 0 0
Hello from level 3: 0 0 1
Hello from level 3: 0 0 2
Hello from level 3: 0 1 0
...
Hello from level 3: 2 1 2
Hello from level 3: 2 2 0
Hello from level 3: 2 2 1
Hello from level 3: 2 2 2
It sounds like you may want to look into recursion.
2015 Edit: Along the same vain as the previous incantation, I made the following package to handle this; https://github.com/BeUndead/NFor
The usage would be as follows
public static void main(String... args) {
NFor<Integer> nfor = NFor.of(Integer.class)
.from(0, 0, 0)
.by(1, 1, 1)
.to(2, 2, 3);
for (Integer[] indices : nfor) {
System.out.println(java.util.Arrays.toString(indices));
}
}
resulting in
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[1, 0, 0]
[1, 0, 1]
[1, 0, 2]
[1, 1, 0]
[1, 1, 1]
[1, 1, 2]
It also supports conditions other than lessThan. The usage there being (with import static NFor.*;):
NFor<Integer> nfor = NFor.of(Integer.class)
.from(-1, 3, 2)
.by(1, -2, -1)
.to(lessThanOrEqualTo(1), greaterThanOrEqualTo(-1), notEqualTo(0));
Resulting in:
[-1, 3, 2]
[-1, 3, 1]
[-1, 1, 2]
[-1, 1, 1]
[-1, -1, 2]
[-1, -1, 1]
[0, 3, 2]
[0, 3, 1]
[0, 1, 2]
[0, 1, 1]
[0, -1, 2]
[0, -1, 1]
[1, 3, 2]
[1, 3, 1]
[1, 1, 2]
[1, 1, 1]
[1, -1, 2]
[1, -1, 1]
Obviously, loops of different lengths and different classes (all boxed, numeric primitives) are supported. The default (if not specified) is from(0, ...).by(1, ...); but a to(...) must be specified.
The NForTest file should demonstrate several different ways to use it.
The basic premise of this being to simply advance the 'indices' each turn rather than use recursion.
You might want to explain what you really want to do.
If the outer for loops are doing nothing but controlling a count, then your nested for loops are simply a more complicated way of iterating by a count that could be handled by a single for loop.
For example:
for (x = 0; x < 10; ++x) {
for (y = 0; y < 5; ++y) {
for (z = 0; z < 20; ++z) {
DoSomething();
}
}
}
Is equivalent to:
for (x = 0; x < 10*5*20; ++x) {
DoSomething();
}
I was actually thinking about this the other day.
An example that is probably not perfect but pretty close to what I think is being asked would be printing out a directory tree
public void printTree(directory) {
for(files in directory) {
print(file);
if(file is directory) {
printTree(file);
}
}
}
this way you end up with a stack of for loops nested inside each other, without the hassle of figuring out exactly how they should go together.
The essential idea behind nesting loops is multiplication.
Expanding on Michael Burr's answer, if the outer for loops are doing nothing but controlling a count, then your nested for loops over n counts are simply a more complicated way of iterating over the product of the counts with a single for loop.
Now, let's extend this idea to Lists. If you're iterating over three lists in nested loops, this is simply a more complicated way of iterating over the product of the lists with a single loop. But how do you express the product of three lists?
First, we need a way of expressing the product of types. The product of two types X and Y can be expressed as a generic type like P2<X, Y>. This is just a value that consists of two values, one of type X, the other of type Y. It looks like this:
public abstract class P2<A, B> {
public abstract A _p1();
public abstract B _p2();
}
For a product of three types, we just have P3<A, B, C>, with the obvious third method. A product of three lists, then, is achieved by distributing the List functor over the product type. So the product of List<X>, List<Y>, and List<Z> is simply List<P3<X, Y, Z>>. You can then iterate over this list with a single loop.
The Functional Java library has a List type that supports multiplying lists together using first-class functions and product types (P2, P3, etc. which are also included in the library).
For example:
for (String x : xs) {
for (String y : ys) {
for (String z : zs) {
doSomething(x, y, z);
}
}
}
Is equivalent to:
for (P3<String, String, String> p : xs.map(P.p3()).apply(ys).apply(zs)) {
doSomething(p._1(), p._2(), p._3());
}
Going further with Functional Java, you can make doSomething first-class, as follows. Let's say doSomething returns a String:
public static final F<P3<String, String, String>, String> doSomething =
new F<P3<String, String, String>, String>() {
public String f(final P3<String, String, String> p) {
return doSomething(p._1(), p._2(), p._3());
}
};
Then you can eliminate the for-loop altogether, and collect the results of all the applications of doSomething:
List<String> s = xs.map(P.p3()).apply(ys).apply(zs).map(doSomething);
Problem needs more specification. Maybe recursion will help you, but keep in mind that recursion is almost always an alternative to iteration, and vice versa. It may be that a 2-level nested loop can be sufficient for your needs. Just let us know what problem you're trying to solve.
The neatest general approach I could come up with in Java 7 is
// i[0] = 0..1 i[1]=0..3, i[2]=0..4
MultiForLoop.loop( new int[]{2,4,5}, new MultiForLoop.Callback() {
void act(int[] i) {
System.err.printf("%d %d %d\n", i[0], i[1], i[2] );
}
}
Or in Java 8:
// i[0] = 0..1 i[1]=0..3, i[2]=0..4
MultiForLoop.loop( new int[]{2,4,5},
i -> { System.err.printf("%d %d %d\n", i[0], i[1], i[2]; }
);
An implementation that supports this is:
/**
* Uses recursion to perform for-like loop.
*
* Usage is
*
* MultiForLoop.loop( new int[]{2,4,5}, new MultiForLoop.Callback() {
* void act(int[] indices) {
* System.err.printf("%d %d %d\n", indices[0], indices[1], indices[2] );
* }
* }
*
* It only does 0 - (n-1) in each direction, no step or start
* options, though they could be added relatively trivially.
*/
public class MultiForLoop {
public static interface Callback {
void act(int[] indices);
}
static void loop(int[] ns, Callback cb) {
int[] cur = new int[ns.length];
loop(ns, cb, 0, cur);
}
private static void loop(int[] ns, Callback cb, int depth, int[] cur) {
if(depth==ns.length) {
cb.act(cur);
return;
}
for(int j = 0; j<ns[depth] ; ++j ) {
cur[depth]=j;
loop(ns,cb, depth+1, cur);
}
}
}
If you are having a general nested-loop structure like:
for(i0=0;i0<10;i0++)
for(i1=0;i1<10;i1++)
for(i2=0;i2<10;i2++)
....
for(id=0;id<10;id++)
printf("%d%d%d...%d\n",i0,i1,i2,...id);
where i0,i1,i2,...,id are loop variables and d is the depth of the nested loop.
Equivalent Recursion Solution:
void nestedToRecursion(counters,level){
if(level == d)
computeOperation(counters,level);
else
{
for (counters[level]=0;counters[level]<10;counters[level]++)
nestedToRecursion(counters,level+1);
}
}
void computeOperation(counters,level){
for (i=0;i<level;i++)
printf("%d",counters[i]);
printf("\n");
}
counters is an array of size d, representing the corresponding variables i0,i1,i2,...id respectively int counters[d].
nestedToRecursion(counters,0);
Similarly we can convert other variables like initializing of recursion or ending by using arrays for them, i.e. we could have initial[d], ending[d].
A Java 8 solution based on streams:
public static Stream<int[]> nest(Supplier<IntStream> first, Supplier<IntStream>... streams) {
Stream<int[]> result = first.get().mapToObj(i -> new int[]{i});
for (Supplier<IntStream> s : streams) {
result = nest(result, s);
}
return result;
}
private static Stream<int[]> nest(Stream<int[]> source, Supplier<IntStream> target) {
return source.flatMap(b -> target.get().mapToObj(i -> {
int[] result = new int[b.length + 1];
System.arraycopy(b, 0, result, 0, b.length);
result[b.length] = i;
return result;
}));
}
Another one which is not thread-safe, but avoid extra copies:
public static Stream<int[]> nest(Supplier<IntStream>... streams) {
final int[] buffer = new int[streams.length];
Stream<int[]> result = Stream.of(buffer);
for (int n = 0; n < streams.length; n++) {
result = nest(result, streams[n], n);
}
// Might need to perform a copy here, if indices are stored instead of being consumed right away.
// return result.map(b -> Arrays.copyOf(b, b.length));
return result;
}
private static Stream<int[]> nest(Stream<int[]> source, Supplier<IntStream> target, int index) {
return source.flatMap(b -> target.get().mapToObj(i -> {
b[index] = i;
return b;
}));
}
Usage:
nest(
() -> IntStream.range(0, 2),
() -> IntStream.range(0, 2),
() -> IntStream.range(0, 3))
.forEach(indices -> System.out.println( Arrays.toString(indices)));
Output:
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[1, 0, 0]
[1, 0, 1]
[1, 0, 2]
[1, 1, 0]
[1, 1, 1]
[1, 1, 2]
public void recursiveFor(Deque<Integer> indices, int[] ranges, int n) {
if (n != 0) {
for (int i = 0; i < ranges[n-1]; i++) {
indices.push(i);
recursiveFor(indices, ranges, n-1);
indices.pop();
}
}
else {
// inner most loop body, access to the index values thru indices
System.out.println(indices);
}
}
Sample call:
int[] ranges = {2, 2, 2};
recursiveFor(new ArrayDeque<Integer>(), ranges, ranges.length);
String fors(int n){
StringBuilder bldr = new StringBuilder();
for(int i = 0; i < n; i++){
for(int j = 0; j < i; j++){
bldr.append('\t');
}
bldr.append("for() {\n");
}
for(int i = n-1; i >= 0; i--){
for(int j = 0; j < i; j++){
bldr.append('\t');
}
bldr.append("}\n");
}
return bldr.toString();
}
Creates a nice nested for-loop skeleton ;-)
Not completely serious and i'm aware that a recursive solution would have been more elegant.
my first time answering a question but i felt like i needed to share this info
of
`
for (x = 0; x < base; ++x) {
for (y = 0; y < loop; ++y) {
DoSomething();
}
}
being equivalent to
for (x = 0; x < base*loop; ++x){
DoSomething();
}
so if you wanted an n number of nests, it can be written using division between base and loop so it could look something as simple as this:
char[] numbs = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
public void printer(int base, int loop){
for (int i = 0; i < pow(base, loop); i++){
int remain = i;
for (int j = loop-1; j >= 0; j--){
int digit = remain/int(pow(base, j));
print(numbs[digit]);
remain -= digit*pow(base, j);
}
println();
}
}
so if you were to type printer(10, 2); it would print out:
00
01
02
03
04
...
97
98
99
This worked for me really nice - I had to select from some alternatives, which were stored in myAlternativePaths and the basic idea is that I was trying to construct next selection, and when there was an "overflow" in one dimension / component, you just reinitialize that dimension and add one to the next.
public boolean isValidAlternativeSelection (int[] alternativesSelected) {
boolean allOK = true;
int nPaths= myAlternativePaths.size();
for (int i=0; i<nPaths; i++) {
allOK=allOK & (alternativesSelected[i]<myAlternativePaths.get(i).myAlternativeRoutes.size());
}
return allOK;
}
public boolean getNextValidAlternativeSelection (int[] alternativesSelected) {
boolean allOK = true;
int nPaths= myAlternativePaths.size();
alternativesSelected[0]=alternativesSelected[0]+1;
for (int i=0; i<nPaths; i++) {
if (alternativesSelected[i]>=myAlternativePaths.get(i).myAlternativeRoutes.size()) {
alternativesSelected[i]=0;
if(i<nPaths-1) {
alternativesSelected[i+1]=alternativesSelected[i+1]+1;
} else {
allOK = false;
}
}
// allOK=allOK & (alternativesSelected[i]<myAlternativePaths.get(i).myAlternativeRoutes.size());
}
return allOK;
}
I also tried to solve this problem and eventually have created this simple solution.
For example, suppose we need to generate loops like this dynamically:
for (int i = 0; i < 2; i++) {
for (int j = 1; j < 3; j++) {
for (int k = 2; k < 4; k++) {
System.out.println(Arrays.asList(i, j, k));
}
}
}
So, we can implement it with a such builder:
new Loops()
.from(0).to(2)
.from(1).to(3)
.from(2).to(4)
.action(System.out::println);
The result of execution:
[0, 1, 2]
[0, 1, 3]
[0, 2, 2]
[0, 2, 3]
[1, 1, 2]
[1, 1, 3]
[1, 2, 2]
[1, 2, 3]
I hope it will useful for someone else too.
In case if you want to work on data and not just numbers. Following solution could be tried:
class WordGenerator {
//My custom spell checker.
//It returns an empty string if the word is not there in dictionary
public static MySpellChecker spellCheck;
public static void main(String args[]) throws Exception {
spellCheck = new MySpellChecker();
List<String> consonants = List.of("c","t");
List<String> vowels = List.of("a","o","");
//adding to this list will increase nesting
List<List<String>> input = new ArrayList<>();
input.add(consonants);
input.add(vowels);
input.add(vowels);
input.add(consonants);
MyForLoop fLoop = new MyForLoop(input.listIterator(), //for nesting loops
new ArrayList<String>(), //loop state
//action to perform in innermost loop
(state)->spellCheck.check(String.join("", state)));
//start execution
fLoop.accept("");
//print results
System.out.println("No of iterations: " + fLoop.getResult().size());
System.out.println("\nFound words: " + String.join(", ", fLoop.getResult()));
}
}
class MyForLoop implements Consumer<String> {
private static List<String> result = new ArrayList<>();
private ListIterator<List<String>> itr;
private Function<List<String>, String> action;
private List<String> state = new ArrayList<>();
public MyForLoop(ListIterator<List<String>> itr, List<String> collected, Function<List<String>, String> action) {
this.itr = itr;
this.action = action;
state = new ArrayList<>(collected);
}
#Override
public void accept(String s) {
if(!s.isBlank())
state.add(s);
if(itr.hasNext()) {
itr.next().stream().forEach(new MyForLoop(itr, state, action));
if(!state.isEmpty())
state.remove(state.size()-1);
itr.previous();
} else {
result.add(action.apply(state));
state.remove(state.size()-1);
}
}
public static List<String> getResult() {
return result;
}
}
Output:
No of iterations: 36
Found words: , , , , , cat, , coat, , coot, , cot, , , , , , , , , , , , tat, , toat, , toot, toc, tot, , , , , ,
Here the code is generating words starting and ending with 'c' and 't', with at max two vowels in between them. You change sequence in input list to change word creation.
The MyForLoop object maintains a state list, that holds current iteration state. Each element of the state list gives state of corresponding level of the nested for loop. The state can be used in action, that gets executed in inner most loop.
To keep the demo code short and simple I've cut corners.😋 It can be improved in many ways.
I've used Jazzy library to check spellings.
<dependency>
<groupId>net.sf.jazzy</groupId>
<artifactId>jazzy</artifactId>
<version>0.5.2-rtext-1.4.1-2</version>
</dependency>
In the interest of conciseness I am putting my code here :
void variDepth(int depth, int n, int i) {
cout<<"\n d = "<<depth<<" i = "<<i;
if(!--depth) return;
for(int i = 0;i<n;++i){
variDepth(depth,n,i);
}
}
void testVariDeapth()
{ variDeapth(3, 2,0);
}
Output
d = 3 i = 0
d = 2 i = 0
d = 1 i = 0
d = 1 i = 1
d = 2 i = 1
d = 1 i = 0
d = 1 i = 1

Categories