@Override
	public List<ItemSet<V>> aprioriGen(	List<ItemSet<V>> frequentCandidatesKMinus1) {
		
		Collections.sort(frequentCandidatesKMinus1);
		int allGeneratedCandidatesCounter = 0;
		Set<ItemSet<V>> frequentCandidateSet = new HashSet<ItemSet<V>>();
		// we iterate both itemsets and generate new candidates base on their
		// combinations
		for (int i = 0; i < frequentCandidatesKMinus1.size(); i++) { // make all n*(n-1)/2 combinations
			ItemSet<V> itemSet1 = frequentCandidatesKMinus1.get(i);
			for (int j = i + 1; j < frequentCandidatesKMinus1.size(); j++) {
				ItemSet<V> itemSet2 = frequentCandidatesKMinus1.get(j);

				ItemSet<V> difference = itemSet2.difference(itemSet1);
				Iterator<V> iterator = difference.getItems().iterator();
				while (iterator.hasNext()) {
					V next = iterator.next();
					ItemSet<V> possibleExtensionItemSet = new ItemSet<V>();
					possibleExtensionItemSet.addItem(next);
					ItemSet<V> union = itemSet1.union(possibleExtensionItemSet);

					// we only keep candidates of size k (which is k - 1 + 1)
					if (union.size() != itemSet1.size() + 1) {
						continue;
					}
					allGeneratedCandidatesCounter++;
					getAndCacheSupportForItemset(union);
					frequentCandidateSet.add(union);
				}
			}
		}
		System.out.println(allGeneratedCandidatesCounter
				+ " total, unique itemsets: " + frequentCandidateSet.size());
		return new LinkedList<ItemSet<V>>(frequentCandidateSet);
	}