Read and use nested lists from file in java - java

I have data in this format [ [[22,34,56],[12,31,44],[74,18,53]], [[15,16,18],[90,89,74],[44,32,13]], [[13,15,17],[1,4,7],[88,73,10]]...] inside a text file and I want to read it use the numbers in each of the inner list. So far I am able to read each inner list of list with the code below, how can I extend it to get the numbers? This question only handles the case of reading strings into an array list and I have not found anotheer that deals with my case.
File f = new File("route.txt");
Scanner s = new Scanner(new FileInputStream(f));
s.useDelimiter("]],");
while (s.hasNext()) {
String r = s.next();
System.out.println(r);
}

As mentioned if it is a JSON array, you could do that. But then would need to delve in the resulting data structure for processiong. A do-it-yourself solution:
Path path = Paths.get("route.txt");
byte[] bytes = Files.readAllBytes(path);
String content = new String(bytes, StandardCharsets.ISO_8859_1);
content = content.replace(" ", ""); // So spaces at odd places do not need to be handled.
String[] sequences = content.split("[^\\d,]+"); // Delimit by not: digit or comma.
for (String sequence : sequences) {
if (!sequence.isEmpty()) {
String[] words = sequence.split(",");
int[] numbers = Stream.of(words).mapToInt(Integer::parseInt).toArray();
.. process the sequence(numbers);
}
}

Parse it as a JSON array. I recommend JSON-P.
import java.io.StringReader;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonReader;
// ...
public static void main(String[] args) {
String data = "[ [[22,34,56],[12,31,44],[74,18,53]], "
+ "[[15,16,18],[90,89,74],[44,32,13]], "
+ "[[13,15,17],[1,4,7],[88,73,10]]]";
JsonReader jsonReader = Json.createReader(new StringReader(data));
JsonArray array = jsonReader.readArray();
for (int i = 0; i < array.size(); i++) {
JsonArray subArray = array.getJsonArray(i);
for (int j = 0; j < subArray.size(); j++) {
JsonArray subSubArray = subArray.getJsonArray(j);
for (int k = 0; k < subSubArray.size(); k++) {
System.out.println(String.format("[%d, %d, %d] %d",
i, j, k, subSubArray.getInt(k)));
}
}
}
}
Output:
[0, 0, 0] 22
[0, 0, 1] 34
[0, 0, 2] 56
[0, 1, 0] 12
[0, 1, 1] 31
[0, 1, 2] 44
[0, 2, 0] 74
[0, 2, 1] 18
[0, 2, 2] 53
[1, 0, 0] 15
[1, 0, 1] 16
[1, 0, 2] 18
[1, 1, 0] 90
[1, 1, 1] 89
[1, 1, 2] 74
[1, 2, 0] 44
[1, 2, 1] 32
[1, 2, 2] 13
[2, 0, 0] 13
[2, 0, 1] 15
[2, 0, 2] 17
[2, 1, 0] 1
[2, 1, 1] 4
[2, 1, 2] 7
[2, 2, 0] 88
[2, 2, 1] 73
[2, 2, 2] 10

Related

Coin change problem with a condition to use exactly m coints

I have coins for 10, 30 and 50. But I want to use only M coins to get a given sum.
I have this code (from this as reference) that just find all possible ways to get the total sum without applying the condition of using only M coins.
static long countWays(int coins[], int n, int sum)
{
// Time complexity of this function: O(n*sum)
// Space Complexity of this function: O(sum)
// table[i] will be storing the number of solutions
// for value i. We need sum+1 rows as the table is
// constructed in bottom up manner using the base
// case (sum = 0)
long[] table = new long[sum + 1];
// Initialize all table values as 0
Arrays.fill(table, 0);
// Base case (If given value is 0)
table[0] = 1;
// Pick all coins one by one and update the table[]
// values after the index greater than or equal to
// the value of the picked coin
for (int i = 0; i < n; i++)
for (int j = coins[i]; j <= sum; j++)
table[j] += table[j - coins[i]];
return table[sum];
}
// Driver Function to test above function
public static void main(String args[])
{
int coins[] = { 10, 30, 50 };
int n = coins.length;
int sum = 80;
System.out.println(countWays(coins, n, sum));
}
How can we add that condition for this problem or is there any alternate approach for this.
For example:
M=4 and sum = 80
Output 2.
Explanation:
case 1 : 10*2 + 30*2 = 80 ( used 4 coins i.e. M coins)
case 2 : 10*3 + 50*1 = 80 ( used 4 coins i.e. M coins)
Constraints:
M reaches up to 5000
sum reaches up to 250000
One way to think about this problem is to count in a different base system. You use the number of unique coins as the base. So for your example of 10, 30, and 50, the base would be 3.
Now you need numbers in that base system that have the correct number of digits, which is 4 for your example. Since each digit can be only one of 3 values in base 3 (0, 1, or 2), the total number of possibilites is 3 raised to the power of 4, or 81.
Thus we can count from 0 to 80 in decimal, and convert that decimal number to a four digit base 3 number using stacked repeated division.
Here's what those four digit base 3 numbers would look like:
0 in base 3: [0, 0, 0, 0]
1 in base 3: [0, 0, 0, 1]
2 in base 3: [0, 0, 0, 2]
3 in base 3: [0, 0, 1, 0]
4 in base 3: [0, 0, 1, 1]
5 in base 3: [0, 0, 1, 2]
6 in base 3: [0, 0, 2, 0]
7 in base 3: [0, 0, 2, 1]
8 in base 3: [0, 0, 2, 2]
9 in base 3: [0, 1, 0, 0]
10 in base 3: [0, 1, 0, 1]
11 in base 3: [0, 1, 0, 2]
12 in base 3: [0, 1, 1, 0]
13 in base 3: [0, 1, 1, 1]
14 in base 3: [0, 1, 1, 2]
15 in base 3: [0, 1, 2, 0]
16 in base 3: [0, 1, 2, 1]
17 in base 3: [0, 1, 2, 2]
18 in base 3: [0, 2, 0, 0]
19 in base 3: [0, 2, 0, 1]
20 in base 3: [0, 2, 0, 2]
21 in base 3: [0, 2, 1, 0]
22 in base 3: [0, 2, 1, 1]
23 in base 3: [0, 2, 1, 2]
24 in base 3: [0, 2, 2, 0]
25 in base 3: [0, 2, 2, 1]
26 in base 3: [0, 2, 2, 2]
27 in base 3: [1, 0, 0, 0]
28 in base 3: [1, 0, 0, 1]
29 in base 3: [1, 0, 0, 2]
30 in base 3: [1, 0, 1, 0]
31 in base 3: [1, 0, 1, 1]
32 in base 3: [1, 0, 1, 2]
33 in base 3: [1, 0, 2, 0]
34 in base 3: [1, 0, 2, 1]
35 in base 3: [1, 0, 2, 2]
36 in base 3: [1, 1, 0, 0]
37 in base 3: [1, 1, 0, 1]
38 in base 3: [1, 1, 0, 2]
39 in base 3: [1, 1, 1, 0]
40 in base 3: [1, 1, 1, 1]
41 in base 3: [1, 1, 1, 2]
42 in base 3: [1, 1, 2, 0]
43 in base 3: [1, 1, 2, 1]
44 in base 3: [1, 1, 2, 2]
45 in base 3: [1, 2, 0, 0]
46 in base 3: [1, 2, 0, 1]
47 in base 3: [1, 2, 0, 2]
48 in base 3: [1, 2, 1, 0]
49 in base 3: [1, 2, 1, 1]
50 in base 3: [1, 2, 1, 2]
51 in base 3: [1, 2, 2, 0]
52 in base 3: [1, 2, 2, 1]
53 in base 3: [1, 2, 2, 2]
54 in base 3: [2, 0, 0, 0]
55 in base 3: [2, 0, 0, 1]
56 in base 3: [2, 0, 0, 2]
57 in base 3: [2, 0, 1, 0]
58 in base 3: [2, 0, 1, 1]
59 in base 3: [2, 0, 1, 2]
60 in base 3: [2, 0, 2, 0]
61 in base 3: [2, 0, 2, 1]
62 in base 3: [2, 0, 2, 2]
63 in base 3: [2, 1, 0, 0]
64 in base 3: [2, 1, 0, 1]
65 in base 3: [2, 1, 0, 2]
66 in base 3: [2, 1, 1, 0]
67 in base 3: [2, 1, 1, 1]
68 in base 3: [2, 1, 1, 2]
69 in base 3: [2, 1, 2, 0]
70 in base 3: [2, 1, 2, 1]
71 in base 3: [2, 1, 2, 2]
72 in base 3: [2, 2, 0, 0]
73 in base 3: [2, 2, 0, 1]
74 in base 3: [2, 2, 0, 2]
75 in base 3: [2, 2, 1, 0]
76 in base 3: [2, 2, 1, 1]
77 in base 3: [2, 2, 1, 2]
78 in base 3: [2, 2, 2, 0]
79 in base 3: [2, 2, 2, 1]
80 in base 3: [2, 2, 2, 2]
The integer in each resulting array (the base 3 number) represents which coin from the original coin values should go in that spot (0 = 10, 1 = 30, 2 = 50).
For example, the number 61 in decimal is 2021 in base 3:
61 in base 3: [2, 0, 2, 1]
The resulting coin combination for that number would be:
50, 10, 50, 30
Here's the code that generated the list of base 3 numbers above:
import java.util.Arrays;
class Main {
public static void main(String[] args) {
int sum = 80;
int numCoins = 4;
int[] coins = new int[]{10, 30, 50};
int base = coins.length;
int combos = (int)Math.pow(base, numCoins);
int[][] combinations = new int[combos][];
for(int d=0; d<combos; d++) {
combinations[d] = convertToBase(d, base, numCoins);
System.out.println(d + " in base " + base + ": " + Arrays.toString(combinations[d]));
}
}
public static int[] convertToBase(int decimalNumber, int base, int numDigits) {
int[] digits = new int[numDigits];
int index = digits.length - 1;
int quotient = decimalNumber;
while (quotient > 0) {
digits[index] = quotient % base;
index--;
quotient = quotient / base;
}
return digits;
}
}
Now that you have all possible combinations of four coins, you need to add up the values from each combo and see if they add up to 80.
Here's a new main() to do just that:
public static void main(String[] args) {
int sum = 80;
int numCoins = 4;
int[] coins = new int[]{10, 30, 50};
int base = coins.length;
int combos = (int)Math.pow(base, numCoins);
int[][] combinations = new int[combos][];
for(int d=0; d<combos; d++) {
combinations[d] = convertToBase(d, base, numCoins);
String combo = "";
int curSum = 0;
for(int coinChoice : combinations[d]) {
combo = combo + coins[coinChoice] + " ";
curSum = curSum + coins[coinChoice];
}
if (curSum == sum) {
System.out.println("Coins: " + combo + " = " + curSum);
}
}
}
Producing the following output:
Coins: 10 10 10 50 = 80
Coins: 10 10 30 30 = 80
Coins: 10 10 50 10 = 80
Coins: 10 30 10 30 = 80
Coins: 10 30 30 10 = 80
Coins: 10 50 10 10 = 80
Coins: 30 10 10 30 = 80
Coins: 30 10 30 10 = 80
Coins: 30 30 10 10 = 80
Coins: 50 10 10 10 = 80
Notice that there are repeats because the same combination of coin denominations could be put into different positions of the four slots.
If you want to get rid of duplicates, you could SORT the resulting combos and add them to a Hashmap if they don't already exist (add import java.util.HashMap;):
public static void main(String[] args) {
int sum = 80;
int numCoins = 4;
int[] coins = new int[]{10, 30, 50};
int base = coins.length;
int combos = (int)Math.pow(base, numCoins);
int[][] combinations = new int[combos][];
HashMap<String, String> uniqueCombos = new HashMap<String, String>();
for(int d=0; d<combos; d++) {
combinations[d] = convertToBase(d, base, numCoins);
String combo = "";
int curSum = 0;
for(int coinChoice : combinations[d]) {
combo = combo + coins[coinChoice] + " ";
curSum = curSum + coins[coinChoice];
}
if (curSum == sum) {
Arrays.sort(combinations[d]);
String key = Arrays.toString(combinations[d]);
if (!uniqueCombos.containsKey(key)) {
uniqueCombos.put(key, combo);
System.out.println("Coins: " + combo + " = " + curSum);
}
}
}
}
Now we only get the two unique combinations in our output:
Coins: 10 10 10 50 = 80
Coins: 10 10 30 30 = 80
Here is the final version of the entire program:
import java.util.Arrays;
import java.util.HashMap;
class Main {
public static void main(String[] args) {
int sum = 80;
int numCoins = 4;
int[] coins = new int[]{10, 30, 50};
int base = coins.length;
int combos = (int)Math.pow(base, numCoins);
int[][] combinations = new int[combos][];
HashMap<String, String> uniqueCombos = new HashMap<String, String>();
for(int d=0; d<combos; d++) {
combinations[d] = convertToBase(d, base, numCoins);
String combo = "";
int curSum = 0;
for(int coinChoice : combinations[d]) {
combo = combo + coins[coinChoice] + " ";
curSum = curSum + coins[coinChoice];
}
if (curSum == sum) {
Arrays.sort(combinations[d]);
String key = Arrays.toString(combinations[d]);
if (!uniqueCombos.containsKey(key)) {
uniqueCombos.put(key, combo);
System.out.println("Coins: " + combo + " = " + curSum);
}
}
}
}
public static int[] convertToBase(int decimalNumber, int base, int numDigits) {
int[] digits = new int[numDigits];
int index = digits.length - 1;
int quotient = decimalNumber;
while (quotient > 0) {
digits[index] = quotient % base;
index--;
quotient = quotient / base;
}
return digits;
}
}
You want to find all i>=0, j>=0, k>=0 such that:
10i + 30j + 50k = S
i + j + k = M
For any particular k, there's at most one solution for i and j. Solving:
10i + 30j = S - 50k
i + j = M - k
gives:
j = M - i - k
10i + 30j = S - 50k
10i + 30(M - i - k) = S - 50k
10i + 30M - 30i - 30k = S - 50k
-20i = S - 50k - 30M + 30k
-20i = S - 20k - 30M
20i = -S + 20k + 30M
i = (30M + 20k - S) / 20
Now, i is an integer if 30M+20k-S is divisible by 20, which is when 30M-S is divisible by 20. If i is an integer, then j is also an integer.
Now we just need to find the range of k for which i and j are both non-negative.
Well, i>=0 when 30M+20k-S>=0, ie. when 20k >= S-30M, or k >= (S-30M)/20.
And j>=0, when M-i-k>=0, ie. when M-(30M+20k-S)/20 - k >= 0, or 20M-30M-20k+S - 20k >= 0, or 40k <= S-10M, or k <= (S-10M)/40.
So without writing a program, we can solve this problem: if 30M-S is not divisible by 20, then there's no solutions. Otherwise, we find the upper and lower bounds for k so that i and j are non-negative.
For example, when M=4 and sum=80, 30M-S=40 which is divisible by 20, we have i>=0 when k>=(S-30M)/20=(80-120)/20=-2 and j>=0 when k<=(S-10M)/40=(80-40)/40=1. We also need 0<=k<=M, so k=0 and k=1 are the two solutions.
An example program (in Python, but easy to convert to whatever you like):
def ways(M, S):
if (30*M-S) % 20 != 0:
return 0
top = min(M, (S-10*M)//40)
bot = max(0, (S-30*M)//20)
if top < bot:
return 0
return top - bot + 1
// Pick all coins one by one and update the table[]
// values after the index greater than or equal to
// the value of the picked coin
for (int i = 0; i < n; i++)
for (int j = coins[i]; j <= sum; j++)
table[j] += table[j - coins[i]];
The overall direction is correct, Dynamic Programming is the right tool for this problem.
But there's a couple of serious mistakes in your solution:
The outer for-loop should iterate over the coins, but in the snippet above, the outer loop iterates over the amounts (index i represents a particular amount). As a consequence, as the end result you'll get not a number of distinct Combinations, but a number of Permutations because in the approach you've taken two identical sets of coins arranged differently would be taken into account. For example, based on the logic of the code permutations like 10 + 10 + 50 + 10 and 10 + 10 + 10 + 50 would contribute the amount of 80, which not correct according to the problem description.
The second issue is much easier to spot, but nevertheless it's important: you're not checking if the array index to which you're referring to exists, which would lead to an ArrayIndexOutOfBoundsException.
So, the main takeaway - we number the number of Combinations, and for that we need to consider each coin separately from other coins, i.e. the outer loop should perform iteration over the given array of coins.
To make the solution more comprehensible, I'll represent each combination of coins and each group of coin-combinations having the same total amount as objects Combination and Combinations respectively.
The array that would accumulate the result would be of type Combinations[]. Each Combination has two properties: limit and coinCount representing the required and current number of coins respectively. Combinations which coinCount exceeds the limit would be discarded on the fly, the rest would filtered out while producing the resulting value.
public static long countWays(int[] coins, int n, int sum) {
Combinations[] table = new Combinations[sum + 1];
table[0] = Combinations.withOneNoCoinsComb(n);
for (int coin : coins) {
for (int i = 0; i < table.length; i++) {
// no combinations representing this amount or i + coin exceeds the sum
if (table[i] == null || i + coin > sum) continue;
if (table[i + coin] == null) {
table[i + coin] = Combinations.getEmpty(); // creating an empty Combinations instance
}
table[i + coin].addCombinations(table[i]); // adding the combinations from the previous array position representing amount i
}
}
return table[sum].getValidCombCount();
}
Custom classes Combinations and Combination:
public class Combinations {
private List<Combination> comb = new ArrayList<>();
private Combinations() {}
public void addCombinations(Combinations other) {
for (Combination c : other.comb) {
if (c.canAdd()) this.comb.add(Combination.copyOf(c).addCoin());
}
}
public int getValidCombCount() {
return (int) comb.stream().filter(Combination::isValid).count();
}
private static Combinations withOneNoCoinsComb(int limit) {
Combinations oneComb = new Combinations();
oneComb.addCombination(new Combination(limit));
return oneComb;
}
private static Combinations getEmpty() {
return new Combinations();
}
public void addCombination(Combination c) {
comb.add(c);
}
// getters
}
public class Combination {
private final int limit; // m - max number of coins
private int coinCount;
public Combination(int limit) {
this.limit = limit;
}
public Combination(int limit, int coinCount) {
this.limit = limit;
this.coinCount = coinCount;
}
public Combination addCoin() {
coinCount++;
return this;
}
public boolean canAdd() {
return coinCount <= limit;
}
public boolean isValid() {
return coinCount == limit;
}
public static Combination copyOf(Combination c) {
return new Combination(c.getLimit(), c.getCoinCount());
}
// getters
}
main()
public static void main(String[] args) {
System.out.println(countWays(new int[]{10, 30, 50}, 4, 80));
}
Output:
2

Combinations with replacement Java

For the last couple of days, I am trying to solve this problem of combinations with replacement in java. I checked other languages as well maybe it was done in them and I could translate to java but with no luck, so any help greatly appreciated.
So here is the problem(mock interview question) I came upon:
Combine from range 0 - 6(n)
In an array of size r (let's say 3)
So the formula for combinations with replacement is C(n,r)=(n+r−1)! / r!(n−1)!. In this case the combinations will be 84
000
010,
011,
...,
025,
055,
...,
666.
However, I can't get my head around this algorithm WITH REPLACEMENT which is an entirely different story from without replacement.
Thank you again in advance for your help.
Retrieved first version of answer:
You can use nn=(n+1) variants of digit at every of r places, so overall number of combinations is P = nn^r. Note that every combination corresponds to the number in range 0..P-1.
So you can walk through all integer values in range 0..P-1 and represent loop counter in nn-ary system.
Java code
public static void main (String[] args) throws java.lang.Exception
{
int n = 2;
int r = 3;
int nn = n + 1;
int p = 1;
for (int i=0; i<r; i++)
p *= nn;
for (int i=0; i<p; i++){
int t = i;
String comb = "(";
for (int j=0; j<r; j++){
comb = comb + String.format("%2d, ", t % nn);
t = t / nn;
}
comb = comb.substring(0, comb.length()-2) + ')';
System.out.println(comb);
}
}
Python code:
n = 2
r = 3
nn = n + 1
p = nn**r
for V in range(p):
t = V
comb = []
for i in range(r):
d = t % nn
comb.append(d)
t = t // nn
print(comb)
[0, 0, 0]
[1, 0, 0]
[2, 0, 0]
[0, 1, 0]
[1, 1, 0]
[2, 1, 0]
[0, 2, 0]
[1, 2, 0]
[2, 2, 0]
[0, 0, 1]
[1, 0, 1]
[2, 0, 1]
[0, 1, 1]
[1, 1, 1]
[2, 1, 1]
[0, 2, 1]
[1, 2, 1]
[2, 2, 1]
[0, 0, 2]
[1, 0, 2]
[2, 0, 2]
[0, 1, 2]
[1, 1, 2]
[2, 1, 2]
[0, 2, 2]
[1, 2, 2]
[2, 2, 2]
The second version: for combinations with replacement.
Recursive (the simplest way) generation in Python.
def cwrreq(maxlen, maxx, s):
if len(s)== maxlen:
print(s)
else:
for i in range(maxx + 1):
cwrreq(maxlen, i, s + str(i))
def combwithrepl(maxlen, maxval):
cwrreq(maxlen, maxval, "")
combwithrepl(3, 6)
generates 84 combinations
000
100
110
111
200
...
663
664
665
666
Full list for (3,3).
Meaning: there are three indistinguishable boxes and three kinds of paints (say red, green, blue).
000 all boxes are hollow
100 one box is red
110
111 all boxes are red
200
210 one box is green, another is red
211
220
221
222
300
310
311
320
321 all boxes have distinct colors
322
330
331
332
333 all boxes are blue
private static List<int[]> samples(int n, int k) {
if (k < 0 || n < 0) throw new IllegalArgumentException();
if (k == 0) return Collections.emptyList();
List<Integer> set = new ArrayList<>();
for (int i = 0; i < n; i++) set.add(i);
if (k == 1) return set.stream().map(i -> new int[]{i}).collect(Collectors.toList());
List<int[]> previous = samples(n, k - 1);
List<int[]> out = new ArrayList<>();
for (int i : set) for (int[] array : previous) out.add(glue(i, array));
return out;
}
private static int[] glue(int i, int[] array) {
int[] out = new int[array.length + 1];
out[0] = i;
System.arraycopy(array, 0, out, 1, array.length);
return out;
}
e.g.,
for (int[] sample : samples(2, 3)) {
System.out.println(Arrays.toString(sample));
}
yields
[0, 0, 0]
[0, 0, 1]
[0, 1, 0]
[0, 1, 1]
[1, 0, 0]
[1, 0, 1]
[1, 1, 0]
[1, 1, 1]
and
for (int[] sample : samples(4, 2)) {
System.out.println(Arrays.toString(sample));
}
yields
[0, 0]
[0, 1]
[0, 2]
[0, 3]
[1, 0]
[1, 1]
[1, 2]
[1, 3]
[2, 0]
[2, 1]
[2, 2]
[2, 3]
[3, 0]
[3, 1]
[3, 2]
[3, 3]

connecting points in n-dimensional hyper cube

I am experimenting with creating 3d like sketches in processing without using the p3d renderer. I have managed to make a cube but for it I hardcoded all the coordinates and connections and once you want to add another dimension it begins to get a little boring. So I have created a function to create all the coordinates:
float[][] cube(int dims, float w) {
int outputSize = (int)pow(2, dims);
float[] temp = new float[dims];
float[][] res = new float[outputSize][dims];
Arrays.fill(temp, w);
res[0] = temp.clone();
for (int i = 0; i < outputSize - 1; i++) {
for (int j = dims - 1; true; j--) {
temp[j] *= -1;
if (temp[j] < 0) {
break;
}
}
res[i + 1] = temp.clone();
}
return res;
}
It simply works by using binary so the inputs (2, 1) cube would be:
[[1, 1], [1, -1], [-1, 1], [-1, -1]]
It works fine but the problem is that It only returns the corners but not witch corner to connect but I can't find an efficient way to do that. I need another function that returns what to indices to connect.
Here is an example of what the function should do given the array above:
[[0, 1], [1, 3], [3, 2], [2, 0]]
(the inner arrays may be in a different order)
Is there any known algorithm to connect the corners of a n-dimensional cube?
I am ok with changing the other function if some other point generation helps.
Here is a way to iteratively generate the coordinates and indices together:
Start with a cube of dimension n
Make two copies of the cube, and place one at each of the extremal coordinates (e.g. -1 and +1) on the n + 1-th axis
Make edges to join each pair of corresponding vertices on the cubes
You already know that the number of vertices V(n) = 2^n. Since the number of edges added to an n + 1 cube is equal to this (all corresponding vertex pairs), plus those of the copied n cube, the recurrence relation for the number of edges is:
E(n) = 2 * E(n - 1) + V(n - 1) // copies + joining edges
E(1) = 1 // base case for n = 1
--> E(n) = n * 2^(n - 1)
n | E(n)
-------------
1 | 1
2 | 4
3 | 12
4 | 32
5 | 80
This allows one to pre-allocate the number of required edges and calculate index offsets when copying the new cube / adding new edges.
Code:
// edge index
class Edge
{
public int A, B;
public Edge(int a, int b)
{
A = a; B = b;
}
public Edge shift(int n)
{
return new Edge(A + n, B + n);
}
}
// cube class
class Cube
{
// I'll leave out the get-functions etc here
private float[][] m_verts;
private Edge[] m_edges;
public Cube(float[][] v, Edge[] e)
{
m_verts = v;
m_edges = e;
}
}
Cube cube_N(int dims, float w)
{
// base case
if (dims < 1)
return null;
// calculate buffer sizes
int dpow2 = 1 << dims;
int numVerts = dpow2;
int numEdges = dims * (dpow2 / 2);
// buffers
float[] temp = new float[dims];
float[][] verts = new float[numVerts][];
Edge[] edges = new Edge[numEdges];
// base case creation
Arrays.fill(temp, w);
verts[0] = temp.clone();
edges[0] = new Edge(0, 1);
// iterative step
for (int i = 0; i < dims; i++)
{
int nV = 1 << i;
int nE = i * (nV / 2);
// copy + shift vertices
for (int j = 0; j < nV; j++)
{
float[] v = verts[j].clone();
v[i] = -w;
verts[nV + j] = v;
}
// copy + shift previous edges
for (int j = 0; j < nE; j++)
{
edges[nE + j] = edges[j].shift(nV);
}
// create new edges to join cube copies
int off = nE * 2;
for (int j = 0; j < nV; j++)
{
edges[off + j] = new Edge(j, nV + j);
}
}
return new Cube(verts, edges);
}
Results for n = 3:
verts:
[1, 1, 1], [-1, 1, 1], [1, -1, 1], [-1, -1, 1],
[1, 1, -1], [-1, 1, -1], [1, -1, -1], [-1, -1, -1]
edges:
[0, 1], [2, 3], [0, 2], [1, 3], [4, 5], [6, 7],
[4, 6], [5, 7], [0, 4], [1, 5], [2, 6], [3, 7]
Results for n = 4:
verts:
[1, 1, 1, 1], [-1, 1, 1, 1], [1, -1, 1, 1], [-1, -1, 1, 1],
[1, 1, -1, 1], [-1, 1, -1, 1], [1, -1, -1, 1], [-1, -1, -1, 1],
[1, 1, 1, -1], [-1, 1, 1, -1], [1, -1, 1, -1], [-1, -1, 1, -1],
[1, 1, -1, -1], [-1, 1, -1, -1], [1, -1, -1, -1], [-1, -1, -1, -1]
edges:
[0 , 1], [2 , 3], [0 , 2], [1 , 3], [4, 5], [6 , 7], [4 , 6], [5 , 7],
[0 , 4], [1 , 5], [2 , 6], [3 , 7], [8, 9], [10, 11], [8 , 10], [9 , 11],
[12, 13], [14, 15], [12, 14], [13, 15], [8, 12], [9 , 13], [10, 14], [11, 15],
[0 , 8], [1 , 9], [2 , 10], [3 , 11], [4, 12], [5 , 13], [6 , 14], [7 , 15]

how to write n-level embeded loop with java

Given M integers (N1, N2, Nm), I want to write a N-level embedded loop like following :
for (int a = 0; a < N1; a++)
for (int b = 0; b < N2; b++)
for (int c = 0; c < N3; c++)
....
for (int m = 0; m < Nm; m++)
operation
Since M is a variable, I cannot write fixed number level for-loop. What tricks could help ?
No need for recursion. Instead, think of each iterator as a digit in a number. When you increment the number, you increment the last digit, and if it exceeds the limit (normally 10), it's set to 0, and the digit to the left of it is increased, repeating the overflow logic.
In this case, each "digit" is an independent counter, each with their own "limit", i.e. the value of the given Nx. If you store those limit values in an array, and keep the counters in a same-size array, the logic is fairly simple.
Here is an example of an optimized version, that uses a label to exit directly from a nested loop:
int[] n = { 3, 4, 5 }; // m = 3: N1 = 3, N2 = 4, N3 = 5
int[] i = new int[n.length]; // All "digits" are 0
LOOP: for (;;) {
// operation using i[] here, e.g.
System.out.println(Arrays.toString(i));
// Process "digits" from last to first
for (int j = i.length - 1; ; j--) {
if (j < 0) // Exit main loop if first "digit" overflowed
break LOOP;
if (++i[j] < n[j]) // Increment "digit", and if not overflowed:
break; // exit digit-loop, i.e. loop back to process
i[j] = 0; // Reset "digit" to 0, then process next (to left) "digit"
}
}
Output
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 0, 3]
[0, 0, 4]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[0, 1, 3]
[0, 1, 4]
[0, 2, 0]
[0, 2, 1]
[0, 2, 2]
[0, 2, 3]
[0, 2, 4]
[0, 3, 0]
[0, 3, 1]
[0, 3, 2]
[0, 3, 3]
[0, 3, 4]
[1, 0, 0]
[1, 0, 1]
[1, 0, 2]
[1, 0, 3]
[1, 0, 4]
[1, 1, 0]
[1, 1, 1]
[1, 1, 2]
[1, 1, 3]
[1, 1, 4]
[1, 2, 0]
[1, 2, 1]
[1, 2, 2]
[1, 2, 3]
[1, 2, 4]
[1, 3, 0]
[1, 3, 1]
[1, 3, 2]
[1, 3, 3]
[1, 3, 4]
[2, 0, 0]
[2, 0, 1]
[2, 0, 2]
[2, 0, 3]
[2, 0, 4]
[2, 1, 0]
[2, 1, 1]
[2, 1, 2]
[2, 1, 3]
[2, 1, 4]
[2, 2, 0]
[2, 2, 1]
[2, 2, 2]
[2, 2, 3]
[2, 2, 4]
[2, 3, 0]
[2, 3, 1]
[2, 3, 2]
[2, 3, 3]
[2, 3, 4]
The same solution as #Andreeas', just with more explanations (he was faster in posting the answer, I'm adding mine to give myself a reason for the time I spent with the explanations):
import java.util.Arrays;
public class Multiloop {
static public void doSomething(int... maxIndexes) {
// quick check: if any of the maxIndexes is zeo or less
// there's a snowball in a furnace chance for the most inner loop
// to get executed
for(int i=0; i<maxIndexes.length; i++) {
if(maxIndexes[i]<=0) {
return; // nothing to do
}
}
// java guarantees all of then are zero after allocation
int multiIndex[]=new int[maxIndexes.length];
int currIndexPos=maxIndexes.length-1; // start looping with the last
do {
// this happens when the current index reached its correspondent maximum
// which of course is maxIndexes[currIndexPos]-1
while(
currIndexPos>=0 &&
multiIndex[currIndexPos]>=maxIndexes[currIndexPos]-1
) {
currIndexPos--; // search for the prev one to increment
}
if(currIndexPos<0) {
// all the indexes have reached their max value, we are done
break;
}
// if it's not the last index, we need to increment the current one
// and reset to zero all the others following it
if(currIndexPos<maxIndexes.length-1) {
// if not at the max value, then it's safe to increment it
multiIndex[currIndexPos]++;
Arrays.fill(multiIndex, currIndexPos+1, maxIndexes.length, 0);
}
// and now all multicycle indexes are to their proper value
// we reset the currIndexPos to the max and the do what we need to do
currIndexPos=maxIndexes.length-1;
/// Cut along the dotted lines and place your own code
/// ✂...✂...✂...✂...✂...✂...✂...✂...✂...✂
{ // the inner-most cycle, using the multicycle indexes as necessary
// replace it with what you need here
// **** Just don't screw up the currIndexPos!!!
// **** unless you know what you are doing
// **** (e.g. breaking any of the "cycles" on the way)
char nameForIndex='a';
for(int i=0; i<maxIndexes.length; i++) {
if(i>0) {
System.out.print(',');
}
System.out.print(nameForIndex+"="+multiIndex[i]);
nameForIndex++;
}
System.out.println();
}
// ✂...✂...✂...✂...✂...✂...✂...✂...✂...
multiIndex[currIndexPos]++;
} while(true); // the exit condition is handled at the cycle start anyway
}
static public void main(String args[]) {
// a triple cycle with their respective max indexes
doSomething(2,4,3);
}
}
Output:
a=0,b=0,c=0
a=0,b=0,c=1
a=0,b=0,c=2
a=0,b=1,c=0
a=0,b=1,c=1
a=0,b=1,c=2
a=0,b=2,c=0
a=0,b=2,c=1
a=0,b=2,c=2
a=0,b=3,c=0
a=0,b=3,c=1
a=0,b=3,c=2
a=1,b=0,c=0
a=1,b=0,c=1
a=1,b=0,c=2
a=1,b=1,c=0
a=1,b=1,c=1
a=1,b=1,c=2
a=1,b=2,c=0
a=1,b=2,c=1
a=1,b=2,c=2
a=1,b=3,c=0
a=1,b=3,c=1
a=1,b=3,c=2
How about using recursive:
int recursive_loop(int var_M){
if(var_M == destination) return 0;
else{
for(int i=0;i<var_M || recursive_loop(var_M+1) ; i++){
// Do operation here
}
}
}
I tested with C , it work.

Permutation between two vectors

I´m studying some techniques of algorithms and got stucked in one problem, I need to do a permutation between two groups. For example:
[1,2,3] e [5,6,7]
Need to generate:
[5,2,3] e [1,6,7]
[5,6,3] e [1,2,7]
........
And so on.
From this what I've done so far is do a permutation in one vector between yourself.
Passing one vector [1,2,3]. Generate the answer:
123
132
213
231
321
312
Based on the code below:
public void permutar(int[] num, int idx) {
for (int i = idx; i < num.length; i++) {
swap(num, i, idx);
permutar(num, idx + 1);
swap(num, i, idx);
}
if (idx == num.length - 1) {
for (int i = 0; i < num.length; i++) {
System.out.print(num[i]);
}
System.out.println("");
}
}
public void swap(int[] num, int a, int b) {
int aux = num[a];
num[a] = num[b];
num[b] = aux;
}
How to do a permutation between this two vectors?
Although you did not precisely describe what you are looking for, and attempt to answer: It seems like you are just looking for all 3-element subsets of the input (1,2,3,5,6,7). Each subset is the first vector of one solution, and the respective remaining elements the other vector.
Here is an example how this may be computed, based on a ChoiceIterable utility class that I wrote a while ago:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
public class CombinationsOfVectors
{
public static void main(String[] args)
{
List<Integer> input = Arrays.asList(1,2,3,5,6,7);
ChoiceIterable<Integer> c = new ChoiceIterable<Integer>(3, input);
for (List<Integer> v0 : c)
{
Set<Integer> s = new LinkedHashSet<Integer>(input);
s.removeAll(v0);
List<Integer> v1 = new ArrayList<Integer>(s);
System.out.println(v0+" and "+v1);
}
}
}
// From https://github.com/javagl/Combinatorics/blob/master/src/
// main/java/de/javagl/utils/math/combinatorics/ChoiceIterable.java
// See the GitHub repo for a commented version
class ChoiceIterable<T> implements Iterable<List<T>>
{
private final List<T> input;
private final int sampleSize;
private final long numElements;
public ChoiceIterable(int sampleSize, List<T> input)
{
this.sampleSize = sampleSize;
this.input = input;
long nf = factorial(input.size());
long kf = factorial(sampleSize);
long nmkf = factorial(input.size() - sampleSize);
long divisor = kf * nmkf;
long result = nf / divisor;
numElements = result;
}
private static long factorial(int n)
{
long f = 1;
for (long i = 2; i <= n; i++)
{
f = f * i;
}
return f;
}
#Override
public Iterator<List<T>> iterator()
{
return new Iterator<List<T>>()
{
private int current = 0;
private final int chosen[] = new int[sampleSize];
{
for (int i = 0; i < sampleSize; i++)
{
chosen[i] = i;
}
}
#Override
public boolean hasNext()
{
return current < numElements;
}
#Override
public List<T> next()
{
if (!hasNext())
{
throw new NoSuchElementException("No more elements");
}
List<T> result = new ArrayList<T>(sampleSize);
for (int i = 0; i < sampleSize; i++)
{
result.add(input.get(chosen[i]));
}
current++;
if (current < numElements)
{
increase(sampleSize - 1, input.size() - 1);
}
return result;
}
private void increase(int n, int max)
{
if (chosen[n] < max)
{
chosen[n]++;
for (int i = n + 1; i < sampleSize; i++)
{
chosen[i] = chosen[i - 1] + 1;
}
}
else
{
increase(n - 1, max - 1);
}
}
#Override
public void remove()
{
throw new UnsupportedOperationException(
"May not remove elements from a choice");
}
};
}
}
The output in this example will be
[1, 2, 3] and [5, 6, 7]
[1, 2, 5] and [3, 6, 7]
[1, 2, 6] and [3, 5, 7]
[1, 2, 7] and [3, 5, 6]
[1, 3, 5] and [2, 6, 7]
[1, 3, 6] and [2, 5, 7]
[1, 3, 7] and [2, 5, 6]
[1, 5, 6] and [2, 3, 7]
[1, 5, 7] and [2, 3, 6]
[1, 6, 7] and [2, 3, 5]
[2, 3, 5] and [1, 6, 7]
[2, 3, 6] and [1, 5, 7]
[2, 3, 7] and [1, 5, 6]
[2, 5, 6] and [1, 3, 7]
[2, 5, 7] and [1, 3, 6]
[2, 6, 7] and [1, 3, 5]
[3, 5, 6] and [1, 2, 7]
[3, 5, 7] and [1, 2, 6]
[3, 6, 7] and [1, 2, 5]
[5, 6, 7] and [1, 2, 3]
If this is not what you have been looking for, you should describe more clearly and precisely what the intended result is.
(E.g. whether or not
[1, 2, 3] and [5, 6, 7]
and
[5, 6, 7] and [1, 2, 3]
count as different results is up to you, but you may filter the results accordingly)
Your task is equal to list all 3-element subsets of your 6-element set. Since the order inside the 3-Element-set does not matter, you should define an order, like 'the smaller number comes first'.
Then the algorithm gets obvious: list = [1 2 3 5 6 7]
EDIT: Set1 should always be the set with number 1 in it, to avoid symmetrical identical solutions.
For all the numbers i from 2 to 5
for all the numbers j from i+1 to 5
Set1 = {list[1], list[i], list[j]}
Set2 = "the other numbers"
This should give right your ordered list from your 9-element comment.
These are nested loops, obviously.
As mentioned in comments to OP question, you have to generate Combination. The usual usecase is to take some subset of elements from a set. In this problem you take subset which represents elements taken from the first set and the rest will be taken from the second.
To implement combination I recommend a for loop counting from 0 to 2^n (where n is number of elements in one array). Then take this number and represent it in binary. Now each 0 or 1 in binary representation says from which set should be given number (and second set will be exact opposite).
I guess you have this as a homework or mental excercise so code is not included :]

Categories