Resolving method calls from generic object in enhanced for loop - java

This is more than likely a simple question for someone who is more familiar with Java than I am. Here's the gist of my issue:
I have a function that basically generates the possible combinations of the objects contained within an ArrayList. Being that I have multiple objects that need to use this function, the function is screaming at me to be made generic. The issue I'm encountering, though, is that an enhanced for-loop is unable to resolve method calls from the generic iterator. I understand why this happening, but I'm not familiar enough with Java to know how to resolve this issue. In any case, here is my code:
private <T> ArrayList<T> determineIdealOrderCombination(ArrayList<T> orders, int position){
// Local Variable Declarations
List<ArrayList<T>> subsets = new ArrayList<>();
int k = orders.size()+1; // Add one due to the do-while loop
int theoreticalQuantity;
int indexOfMaxProfit;
double maxProfit;
int[] s; // Here we'll keep indices pointing to elements in input array
double[] profits; // Here we'll keep track of the profit of each combination
// Begin searching for valid combinations
do {
// Setup
k--;
s = new int[k];
profits = new double[k];
// Generate combinations
if ( (k <= orders.size()) && (k > 0) ) {
// Set the first index sequence: 0, 1, 2,...
for (int i = 0; (s[i] = i) < k - 1; i++) ;
subsets.add(getSubset(orders, s));
for (; ; ) {
int i;
// Find position of item that can be incremented
for (i = k - 1; i >= 0 && s[i] == orders.size() - k + i; i--) ;
if (i < 0) {
break;
} else {
s[i]++; // increment this item
for (++i; i < k; i++) { // fill up remaining items
s[i] = s[i - 1] + 1;
}
subsets.add(getSubset(orders, s));
}
}
// All combinations have been evaluated, now throw away invalid combinations that violate the upper limit
// and calculate the valid combinations profits.
for (int i = 0; i < subsets.size(); i++) {
// Calculate the final position
theoreticalQuantity = position;
profits[i] = 0;
for (T t : subsets.get(i)) {
theoreticalQuantity += t.getQuantity(); // <-- THE PROBLEM
profits[i] += calculateProjectedProfit(t.getSecurity(), t.getQuantity(), t.getPrice()); // <-- THE PROBLEM
}
if(theoreticalQuantity > _MAX_POSITION_PER_ASSET){
// Negate profits if final position violates the position limit on an asset
profits[i] = Double.MIN_VALUE;
}
}
}
else{
break;
}
}
while( (subsets.size() == 0) );
// Verify that the subset array is not zero - it should never be zero
if(subsets.size() == 0){
return new ArrayList<>();
}
// Return the most profitable combination, if any.
indexOfMaxProfit = -1;
maxProfit = Double.MIN_VALUE;
for(int i = 0; i < profits.length; i++){
if(profits[i] != Double.MIN_VALUE){
if(profits[i] > maxProfit){
maxProfit = profits[i];
indexOfMaxProfit = i;
}
}
}
if( (maxProfit > 0) && (indexOfMaxProfit != -1) ){
return subsets.get(indexOfMaxProfit);
}
else{
return new ArrayList<>();
}
}
Any help would be appreciated.

This is how you tell the compiler that the incoming objects have the relevant methods:
public interface MyCommonInterface {
public int getQuantity();
}
private <T extends MyCommonInterface> ArrayList<T> determineIdealOrderCombination(ArrayList<T> orders, int position) {
As an additional note, i would read some tutorials on generics before attempting to use them. they are a little tricky to get the hang of initially. however, once you put out a little effort to learn the basics, you should be in a much better place to actually utilize them.

Related

Find different index in arrays compare

I'm trying to learn a bit Java with tutorials and currently I'm struggling with piece of code where I should find on which index is difference between arrays (if there is difference at all)
My code
Scanner scanner = new Scanner(System.in);
int[] arrOne = Arrays.stream(scanner.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
int[] arrTwo = Arrays.stream(scanner.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
int sumArrOne = 0;
int index = 0;
boolean diff = false;
for (int k : arrOne) {
if (Arrays.equals(arrOne, arrTwo)) {
sumArrOne += k;
} else {
for (int i : arrTwo) {
if (k != i) {
index = i;
diff = true;
break;
}
}
}
}
if (diff) {
System.out.println("Found difference at " + index + " index.");
} else {
System.out.println("Sum: " + sumArrOne);
}
So, if arrays are identical I'm sum array elements in arrOne. If they are not identical -> must show at which index they are not.
With this code when I input
1 2 3 4 5
1 2 4 3 5
I should get that difference is at index 2 instead I've got index 1.
I'm not quite sure why and would be glad if someone point me out where is my mistake.
I updated your code. Looks like you're misunderstanding the concept of indexes yet.
Use one common index to check with in both arrays, in my example it's simply called i:
import java.util.Arrays;
import java.util.Scanner;
public class BadArray {
static private final int INVALID_INDEX = Integer.MIN_VALUE;
public static void main(final String[] args) {
try (final Scanner scanner = new Scanner(System.in);) {
final int[] arrOne = Arrays.stream(scanner.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
final int[] arrTwo = Arrays.stream(scanner.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
int sumArrOne = 0;
int diffIndex = INVALID_INDEX;
final int minLen = Math.min(arrOne.length, arrTwo.length);
for (int i = 0; i < minLen; i++) {
sumArrOne += arrOne[i];
if (arrOne[i] != arrTwo[i]) {
diffIndex = i;
break;
}
}
if (diffIndex != INVALID_INDEX) {
System.out.println("Found difference at " + diffIndex + " index.");
} else if (arrOne.length != arrTwo.length) {
System.out.println("Arrays are equal but have different length!");
} else {
System.out.println("Sum: " + sumArrOne);
}
}
}
}
I also put the scanner into a try-resource-catch to handle resource releasing properly.
Note you could also do the array lengths comparison right at the start if different array lengths play a more crucial role.
You are trying to find out which index has the first difference so you should iterate via the index rather than using a for-each loop (aka enhanced for loop). The following method should work for this.
/**
* Returns the index of the first element of the two arrays that are not the same.
* Returns -1 if both arrays have the same values in the same order.
* #param left an int[]
* #param right an int[]
* #return index of difference or -1 if none
*/
public int findIndexOfDifference(int[] left, int[] right) {
// short-circuit if we're comparing an array against itself
if (left == right) return -1;
for (int index = 0 ; index < left.length && index < right.length ; ++index) {
if (left[index] != right[index]) {
return index;
}
}
return -1;
}
In your code you compare, where the indexes are different, not the values at the indexes. Also your code has several other issues. I'll try to go through them step by step:
// compare the whole array only once, not inside a loop:
diff = !Arrays.equals(arrOne, arrTwo));
if (!diff) {
// do the summing without a loop
sumArrOne = Arrays.stream(arrOne).sum();
} else {
// find the difference
// it could be the length
index = Math.min(arrOne.length, arrTwo.length);
// or in some different values
for (int i = 0; i < index; i++) { // do a loop with counter
if (arrOne[i] != arrTwo[i]) {
index = i;
break;
}
}
}
It doesn't matter that I set index here above the loop as it's value will be overwritten anyways inside the loop, if relevant.

For k collections all of which have length = N, finding common elements with a O((k-1)*N)

I am supposed to write a code which is supposed to find the common elements existing in k collections of N-elements efficiently. All collections are sorted and they may have various sizes, but let's assume same sizes for the sake of simplicity here. Only thing that counts is the comparisons between elements; that should be less than O((k-1)*N).
I have developed the below code, but in case of mentioned scenario the number of comparisons is about (k-1)NN
Appreciate the help in advance.
//Arrays are sorted and the shortest array is chosen as the query automatically
boolean com;
loop1: for (int i = 0; i < QuetyList.length; ++i) {
com = false;
loop2: for (int k = 0; k < OtherLists.length; ++k) {
com = false;
loop3: for (int y = 0; y < OtherLists[k].size(); ++y) {
++comparisons;
if (QueryList[i].compareTo(OtherLists[k][y]) == 0) {
com = true;
break loop3;
}
++comparisons;
if (QueryList[i].compareTo(OtherLists[k][y]) < 0) {
break;
}
}
if (com == false) {
break;
}
}
if (com == true) {
commons.add(QueryList[i]);
}
}
Sample test
Comparable [] QuetyList = {200,200,200,200};
Comparable [] collection2 = {2,10,50,200};
Comparable [] collection3 = {2,10,40,200};
Comparable [][] OtherLists = {collection2,collection3};
This is for a homework. There is a chance you may have crossed sometime in your education. Thanks in advance.
The basic idea is to keep an index on every list you have, and only advance this index when the value at the index is the smallest among all the lists.
I can't see if it's doable for k lists at once, but it's certainly doable 2 lists at a time, each should take N comparisons, which should give you O(k * N) (k-1 runs of N comparison).
Something like:
public Comparable[] common(Comparable[] a, Comparable[] b) {
// List is more flexible, but the toArray at the end is a bit costly. You can probably figure a better way of doing this.
List<Comparable> res = new ArrayList<>();
int indexA = 0;
int indexB = 0;
while (indexA < a.length && indexB < b.length) {
// Exercice for the reader: replace with compareTo calls
if (a[indexA] == b[indexB]) {
// Common item!
res.add(a[indexA]);
indexA++;
indexB++;
} else if (a[indexA] < b[indexB]) {
// item in A is smaller, try the next
indexA++;
} else {
indexB++;
}
}
return res.toArray(new Comparable[0]);
}
From this, you can group your lists 2 by 2 until only one list remains.

Efficient method to find the second largest even int in an array

The assignment is to create a method that finds the second largest even int in an array of ints. I am restricted from using any methods from any libraries.
Here is my code that works for all cases:
public static int getSecondLargestEven(int[] ary) {
int i;
aryLength = ary.length;
int largestEven = -1;
int secondLargestEven = -1;
for (i = 0; i < aryLength; i++) {
if (ary[i] % 2 == 0) {
if (ary[i] > largestEven) {
if (largestEven != -1)
secondLargestEven = largestEven;
largestEven = ary[i];
} else {
if (ary[i] != largestEven) {
if (secondLargestEven == -1 || ary[i] >= secondLargestEven) {
secondLargestEven = ary[i];
}
}
}
}
}
Prior to calling the methodI require the array to have more than one even else no method call.
So, when secondLargestEven == -1, I know there is a duplicate.
Is there a more efficient (less use of operators, less loops used, less memory allocation) way to accomplish the objective? How can I improve the logic of my code? How can I improve my code overall?
I don't like that I have to assign the magic number -1 to secondLargestEven and largestEven because they are technically named to hold EVENS. Would it be efficient to use a loop to assign a valid even integer in the array to both secondLargestEven and largestEven and THEN proceed to search? Thanks in advance.
You can make the code cleaner by not explicitly checking for the case when the largest and second variables are equal to -1.
Just set these variables to Integer.MIN_VALUE before the loop - this is the same as assuming that there were two additional values in your array that come before all the others, and they both have the value Integer.MIN_VALUE.
public static int secondLargestEven(int[] x) {
int largest = Integer.MIN_VALUE;
int second = Integer.MIN_VALUE;
for (int i = 0; i < x.length; i++) {
if (x[i] % 2 == 0) {
if (x[i] > largest) {
second = largest;
largest = x[i];
} else if (x[i] > second) {
second = x[i];
}
}
}
return second;
}
Edit -- I thought I'd throw in that you can remove one level of nesting by using a continue statement inside the loop to skip the cases where you have an odd integer, although some people would consider this more difficult to understand than the code above.
It's a tradeoff - you use explicit control flow inside the loop (bad) but you remove a nesting level (good).
public static int secondLargestEven(int[] x) {
int largest = Integer.MIN_VALUE;
int second = Integer.MIN_VALUE;
for (int i = 0; i < x.length; i++) {
if (x[i] % 2 != 0)
continue;
if (x[i] > largest) {
second = largest;
largest = x[i];
} else if (x[i] > second)
second = x[i];
}
}
return second;
}
Just a fun thought... in Haskell, this function can be written in one line
import Data.List (sort)
secondLargestEven = (!! 1) . reverse . sort . filter even
or, if you want to be more efficient
import Data.List (sortBy)
import Data.Ord (comparing)
secondLargestEven = (!! 1) . sortBy (comparing negate) . filter even
This is just-for-fun implementation:
public static int secondLargestEven(int[] array) {
Set<Integer> evenSet = new TreeSet<>(Collections.reverseOrder());
for (int n : array) if (n % 2 == 0) evenSet.add(n);
return new ArrayList<>(evenSet).get(1);
}
This method is extremely inefficient (I cant look at it) but returns second largest even number :)
Method works only if array has second largest even number.

How to generate sums of combinations of elements of a set efficiently in terms of time and memory?

I have a random set S of integers and the cardinality (n) of this set may vary from 10 to 1000. I need to store all sums of the nCr combinations of size r generated from this set. Usually r range from 3 to 10.
E.g. if S={102,233,344,442,544,613,71289,836,97657,12} and r=4, Then The sums generated will be {0,1,2,3}=102+233+344+442, {0,1,2,4}=102+233+344+544,....so on.
I implemented a findCombi function (below) in Java which gave me all nCr combinations in terms of r sized sets of indices and then I sifted through these sets in another function to generate the sum of corresponding elements.
But the program is giving heapspace error, probably because of exponential nature and I have 100-5000 of such sets, S. Or may be there is a memory leak?
Is there a faster and lesser-memory consuming way to do it?
Note: dsize=n, combiSize=r
List <List<Integer>> findCombi(int dsize,int combiSize) {
if( (combiSize==0) || (dsize==0) ){
return null;
}
long n=dsize;
int r=combiSize;
for(int i=1;i<combiSize;i++) {
n=n*(dsize-i);
r=r*i;
}
int totalcombi=(int) n/r;
List <List<Integer>> combiData=new ArrayList<>(totalcombi);
int pos;
List <Integer> combi=new ArrayList<>(combiSize);
for(int i=0;i<combiSize;i++) {
combi.add(i,i);
}
combiData.add(new ArrayList<>(combi));
pos=combiSize-1;
while(true) {
if(combi.get(pos)<(dsize-combiSize+pos)) {
combi.set(pos,combi.get(pos)+1);
if(pos==(combiSize-1)) {
combiData.add(new ArrayList<>(combi));
}
else {
combi.set(pos+1,combi.get(pos));
pos++;
}
}
else {
pos--;
}
if(pos==-1) {
break;
}
}
return combiData;
}
I needed something like that earlier, so here is some code adapted from the project I made back then. The method allSums builds a list of indices of size r, which is used to represent all the possible combinations. At each step, the current sum is added to the result set, then the next combination is generated. Since the results are put in a set, there is no way a result could appear twice. I included a main method so you can see it work. I hope this is clear, feel free to ask questions.
import java.util.*;
public class Program {
static private Set<Integer> allSums(List<Integer> values, int r) {
HashSet<Integer> res = new HashSet<>();
if ((values.isEmpty()) || r > values.size()) {
return res;
}
// build the list of indices
List<Integer> li = new ArrayList<>();
for (int i = 0; i < r; i++) {
li.add(i);
}
li.add(values.size()); // artificial last index : number of elements in set
while (true) {
// add the current sum to the result
int sum = 0;
for (int i = 0; i < r; i++) {
sum += values.get(li.get(i));
}
res.add(sum);
// move to the next combination
// first, find the last index that can be incremented
int i = r-1;
while ((i >= 0) && (li.get(i) == li.get(i+1)-1)) {
i--;
}
// was such an index found ?
if (i == -1) {
break; // if not, it's over
}
// increment the last index and set all the next indices to their initial value
li.set(i,li.get(i)+1);
for (int j = i+1; j < r; j++) {
li.set(j, li.get(j-1)+1);
}
}
return res;
}
public static void main(String[] args) {
List<Integer> values = new ArrayList<>();
values.add(10);
values.add(100);
values.add(1000);
values.add(10000);
values.add(100000);
Set<Integer> s = allSums(values, 3);
for (int i : s) {
System.out.println(i);
}
}
}

How to iteratively generate k elements subsets from a set of size n in java?

I'm working on a puzzle that involves analyzing all size k subsets and figuring out which one is optimal. I wrote a solution that works when the number of subsets is small, but it runs out of memory for larger problems. Now I'm trying to translate an iterative function written in python to java so that I can analyze each subset as it's created and get only the value that represents how optimized it is and not the entire set so that I won't run out of memory. Here is what I have so far and it doesn't seem to finish even for very small problems:
public static LinkedList<LinkedList<Integer>> getSets(int k, LinkedList<Integer> set)
{
int N = set.size();
int maxsets = nCr(N, k);
LinkedList<LinkedList<Integer>> toRet = new LinkedList<LinkedList<Integer>>();
int remains, thresh;
LinkedList<Integer> newset;
for (int i=0; i<maxsets; i++)
{
remains = k;
newset = new LinkedList<Integer>();
for (int val=1; val<=N; val++)
{
if (remains==0)
break;
thresh = nCr(N-val, remains-1);
if (i < thresh)
{
newset.add(set.get(val-1));
remains --;
}
else
{
i -= thresh;
}
}
toRet.add(newset);
}
return toRet;
}
Can anybody help me debug this function or suggest another algorithm for iteratively generating size k subsets?
EDIT: I finally got this function working, I had to create a new variable that was the same as i to do the i and thresh comparison because python handles for loop indexes differently.
First, if you intend to do random access on a list, you should pick a list implementation that supports that efficiently. From the javadoc on LinkedList:
All of the operations perform as could be expected for a doubly-linked
list. Operations that index into the list will traverse the list from
the beginning or the end, whichever is closer to the specified index.
An ArrayList is both more space efficient and much faster for random access. Actually, since you know the length beforehand, you can even use a plain array.
To algorithms: Let's start simple: How would you generate all subsets of size 1? Probably like this:
for (int i = 0; i < set.length; i++) {
int[] subset = {i};
process(subset);
}
Where process is a method that does something with the set, such as checking whether it is "better" than all subsets processed so far.
Now, how would you extend that to work for subsets of size 2? What is the relationship between subsets of size 2 and subsets of size 1? Well, any subset of size 2 can be turned into a subset of size 1 by removing its largest element. Put differently, each subset of size 2 can be generated by taking a subset of size 1 and adding a new element larger than all other elements in the set. In code:
processSubset(int[] set) {
int subset = new int[2];
for (int i = 0; i < set.length; i++) {
subset[0] = set[i];
processLargerSets(set, subset, i);
}
}
void processLargerSets(int[] set, int[] subset, int i) {
for (int j = i + 1; j < set.length; j++) {
subset[1] = set[j];
process(subset);
}
}
For subsets of arbitrary size k, observe that any subset of size k can be turned into a subset of size k-1 by chopping of the largest element. That is, all subsets of size k can be generated by generating all subsets of size k - 1, and for each of these, and each value larger than the largest in the subset, add that value to the set. In code:
static void processSubsets(int[] set, int k) {
int[] subset = new int[k];
processLargerSubsets(set, subset, 0, 0);
}
static void processLargerSubsets(int[] set, int[] subset, int subsetSize, int nextIndex) {
if (subsetSize == subset.length) {
process(subset);
} else {
for (int j = nextIndex; j < set.length; j++) {
subset[subsetSize] = set[j];
processLargerSubsets(set, subset, subsetSize + 1, j + 1);
}
}
}
Test code:
static void process(int[] subset) {
System.out.println(Arrays.toString(subset));
}
public static void main(String[] args) throws Exception {
int[] set = {1,2,3,4,5};
processSubsets(set, 3);
}
But before you invoke this on huge sets remember that the number of subsets can grow rather quickly.
You can use
org.apache.commons.math3.util.Combinations.
Example:
import java.util.Arrays;
import java.util.Iterator;
import org.apache.commons.math3.util.Combinations;
public class tmp {
public static void main(String[] args) {
for (Iterator<int[]> iter = new Combinations(5, 3).iterator(); iter.hasNext();) {
System.out.println(Arrays.toString(iter.next()));
}
}
}
Output:
[0, 1, 2]
[0, 1, 3]
[0, 2, 3]
[1, 2, 3]
[0, 1, 4]
[0, 2, 4]
[1, 2, 4]
[0, 3, 4]
[1, 3, 4]
[2, 3, 4]
Here is a combination iterator I wrote recetnly
package psychicpoker;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
public class CombinationIterator<T> implements Iterator<Collection<T>> {
private int[] indices;
private List<T> elements;
private boolean hasNext = true;
public CombinationIterator(List<T> elements, int k) throws IllegalArgumentException {
checkArgument(k<=elements.size(), "Impossible to select %d elements from hand of size %d", k, elements.size());
this.indices = new int[k];
for(int i=0; i<k; i++)
indices[i] = k-1-i;
this.elements = elements;
}
public boolean hasNext() {
return hasNext;
}
private int inc(int[] indices, int maxIndex, int depth) throws IllegalStateException {
if(depth == indices.length) {
throw new IllegalStateException("The End");
}
if(indices[depth] < maxIndex) {
indices[depth] = indices[depth]+1;
} else {
indices[depth] = inc(indices, maxIndex-1, depth+1)+1;
}
return indices[depth];
}
private boolean inc() {
try {
inc(indices, elements.size() - 1, 0);
return true;
} catch (IllegalStateException e) {
return false;
}
}
public Collection<T> next() {
Collection<T> result = new ArrayList<T>(indices.length);
for(int i=indices.length-1; i>=0; i--) {
result.add(elements.get(indices[i]));
}
hasNext = inc();
return result;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
I've had the same problem today, of generating all k-sized subsets of a n-sized set.
I had a recursive algorithm, written in Haskell, but the problem required that I wrote a new version in Java.
In Java, I thought I'd probably have to use memoization to optimize recursion. Turns out, I found a way to do it iteratively. I was inspired by this image, from Wikipedia, on the article about Combinations.
Method to calculate all k-sized subsets:
public static int[][] combinations(int k, int[] set) {
// binomial(N, K)
int c = (int) binomial(set.length, k);
// where all sets are stored
int[][] res = new int[c][Math.max(0, k)];
// the k indexes (from set) where the red squares are
// see image above
int[] ind = k < 0 ? null : new int[k];
// initialize red squares
for (int i = 0; i < k; ++i) { ind[i] = i; }
// for every combination
for (int i = 0; i < c; ++i) {
// get its elements (red square indexes)
for (int j = 0; j < k; ++j) {
res[i][j] = set[ind[j]];
}
// update red squares, starting by the last
int x = ind.length - 1;
boolean loop;
do {
loop = false;
// move to next
ind[x] = ind[x] + 1;
// if crossing boundaries, move previous
if (ind[x] > set.length - (k - x)) {
--x;
loop = x >= 0;
} else {
// update every following square
for (int x1 = x + 1; x1 < ind.length; ++x1) {
ind[x1] = ind[x1 - 1] + 1;
}
}
} while (loop);
}
return res;
}
Method for the binomial:
(Adapted from Python example, from Wikipedia)
private static long binomial(int n, int k) {
if (k < 0 || k > n) return 0;
if (k > n - k) { // take advantage of symmetry
k = n - k;
}
long c = 1;
for (int i = 1; i < k+1; ++i) {
c = c * (n - (k - i));
c = c / i;
}
return c;
}
Of course, combinations will always have the problem of space, as they likely explode.
In the context of my own problem, the maximum possible is about 2,000,000 subsets. My machine calculated this in 1032 milliseconds.
Inspired by afsantos's answer :-)... I decided to write a C# .NET implementation to generate all subset combinations of a certain size from a full set. It doesn't need to calc the total number of possible subsets; it detects when it's reached the end. Here it is:
public static List<object[]> generateAllSubsetCombinations(object[] fullSet, ulong subsetSize) {
if (fullSet == null) {
throw new ArgumentException("Value cannot be null.", "fullSet");
}
else if (subsetSize < 1) {
throw new ArgumentException("Subset size must be 1 or greater.", "subsetSize");
}
else if ((ulong)fullSet.LongLength < subsetSize) {
throw new ArgumentException("Subset size cannot be greater than the total number of entries in the full set.", "subsetSize");
}
// All possible subsets will be stored here
List<object[]> allSubsets = new List<object[]>();
// Initialize current pick; will always be the leftmost consecutive x where x is subset size
ulong[] currentPick = new ulong[subsetSize];
for (ulong i = 0; i < subsetSize; i++) {
currentPick[i] = i;
}
while (true) {
// Add this subset's values to list of all subsets based on current pick
object[] subset = new object[subsetSize];
for (ulong i = 0; i < subsetSize; i++) {
subset[i] = fullSet[currentPick[i]];
}
allSubsets.Add(subset);
if (currentPick[0] + subsetSize >= (ulong)fullSet.LongLength) {
// Last pick must have been the final 3; end of subset generation
break;
}
// Update current pick for next subset
ulong shiftAfter = (ulong)currentPick.LongLength - 1;
bool loop;
do {
loop = false;
// Move current picker right
currentPick[shiftAfter]++;
// If we've gotten to the end of the full set, move left one picker
if (currentPick[shiftAfter] > (ulong)fullSet.LongLength - (subsetSize - shiftAfter)) {
if (shiftAfter > 0) {
shiftAfter--;
loop = true;
}
}
else {
// Update pickers to be consecutive
for (ulong i = shiftAfter+1; i < (ulong)currentPick.LongLength; i++) {
currentPick[i] = currentPick[i-1] + 1;
}
}
} while (loop);
}
return allSubsets;
}
This solution worked for me:
private static void findSubsets(int array[])
{
int numOfSubsets = 1 << array.length;
for(int i = 0; i < numOfSubsets; i++)
{
int pos = array.length - 1;
int bitmask = i;
System.out.print("{");
while(bitmask > 0)
{
if((bitmask & 1) == 1)
System.out.print(array[pos]+",");
bitmask >>= 1;
pos--;
}
System.out.print("}");
}
}
Swift implementation:
Below are two variants on the answer provided by afsantos.
The first implementation of the combinations function mirrors the functionality of the original Java implementation.
The second implementation is a general case for finding all combinations of k values from the set [0, setSize). If this is really all you need, this implementation will be a bit more efficient.
In addition, they include a few minor optimizations and a smidgin logic simplification.
/// Calculate the binomial for a set with a subset size
func binomial(setSize: Int, subsetSize: Int) -> Int
{
if (subsetSize <= 0 || subsetSize > setSize) { return 0 }
// Take advantage of symmetry
var subsetSizeDelta = subsetSize
if (subsetSizeDelta > setSize - subsetSizeDelta)
{
subsetSizeDelta = setSize - subsetSizeDelta
}
// Early-out
if subsetSizeDelta == 0 { return 1 }
var c = 1
for i in 1...subsetSizeDelta
{
c = c * (setSize - (subsetSizeDelta - i))
c = c / i
}
return c
}
/// Calculates all possible combinations of subsets of `subsetSize` values within `set`
func combinations(subsetSize: Int, set: [Int]) -> [[Int]]?
{
// Validate inputs
if subsetSize <= 0 || subsetSize > set.count { return nil }
// Use a binomial to calculate total possible combinations
let comboCount = binomial(setSize: set.count, subsetSize: subsetSize)
if comboCount == 0 { return nil }
// Our set of combinations
var combos = [[Int]]()
combos.reserveCapacity(comboCount)
// Initialize the combination to the first group of set indices
var subsetIndices = [Int](0..<subsetSize)
// For every combination
for _ in 0..<comboCount
{
// Add the new combination
var comboArr = [Int]()
comboArr.reserveCapacity(subsetSize)
for j in subsetIndices { comboArr.append(set[j]) }
combos.append(comboArr)
// Update combination, starting with the last
var x = subsetSize - 1
while true
{
// Move to next
subsetIndices[x] = subsetIndices[x] + 1
// If crossing boundaries, move previous
if (subsetIndices[x] > set.count - (subsetSize - x))
{
x -= 1
if x >= 0 { continue }
}
else
{
for x1 in x+1..<subsetSize
{
subsetIndices[x1] = subsetIndices[x1 - 1] + 1
}
}
break
}
}
return combos
}
/// Calculates all possible combinations of subsets of `subsetSize` values within a set
/// of zero-based values for the set [0, `setSize`)
func combinations(subsetSize: Int, setSize: Int) -> [[Int]]?
{
// Validate inputs
if subsetSize <= 0 || subsetSize > setSize { return nil }
// Use a binomial to calculate total possible combinations
let comboCount = binomial(setSize: setSize, subsetSize: subsetSize)
if comboCount == 0 { return nil }
// Our set of combinations
var combos = [[Int]]()
combos.reserveCapacity(comboCount)
// Initialize the combination to the first group of elements
var subsetValues = [Int](0..<subsetSize)
// For every combination
for _ in 0..<comboCount
{
// Add the new combination
combos.append([Int](subsetValues))
// Update combination, starting with the last
var x = subsetSize - 1
while true
{
// Move to next
subsetValues[x] = subsetValues[x] + 1
// If crossing boundaries, move previous
if (subsetValues[x] > setSize - (subsetSize - x))
{
x -= 1
if x >= 0 { continue }
}
else
{
for x1 in x+1..<subsetSize
{
subsetValues[x1] = subsetValues[x1 - 1] + 1
}
}
break
}
}
return combos
}

Categories