How do you write a recursive method PowerSet(String input) that prints out all possible combinations of a string that is passed to it?
For example: PowerSet("abc") will print out abc, ab, ac, bc, a, b, c
I have seen some recursive solutions with loops, but in this case no loops are allowed.
Any ideas?
Edit: The required method has only one parameter, i.e. String input.
The powerset of abcd is the union of the power-sets of abc, abd, acd (plus the set abcd itself*).
P(`abcd`) = {`abcd`} + P(`abc`) + P(`abd`) + P(`acd`) + P(`bcd`)
* Note that the empty set, which is a member of P(abcd) is also a member of P(abc), P(abd), ... so the equivalence stated above holds.
Recursively, P(abc) = {abc} + P(ab) + P(ac), and so on
A first approach, in pseudocode, could be:
powerset(string) {
add string to set;
for each char in string {
let substring = string excluding char,
add powerset(substring) to set
}
return set;
}
The recursion ends when the string is empty (because it never enters the loop).
If your really want no loops, you will have to convert that loop to another recursion.
Now we want to generate ab, ac and cb from abc
powerset(string) {
add string to set;
add powerset2(string,0) to set;
return set
}
powerset2(string,pos) {
if pos<length(string) then
let substring = (string excluding the char at pos)
add powerset(substring) to set
add powerset2(string,pos+1) to set
else
add "" to set
endif
return set
}
Another approach implement a recursive function P that either removes the first character from its argument, or does not. (Here + means set union, . means concatenation and λ is the empty string)
P(abcd) = P(bcd) + a.P(bcd)
P(bcd) = P(cd) + b.P(cd)
P(cd) = P(d) + c.P(d)
P(d) = λ+d //particular case
Then
P(d) = λ+d
R(cd) = P(d) + c.P(d) = λ + d + c.(λ+d) = λ + d + c + cd
R(bcd) = P(cd) + b.P(cd) = λ + d + c + cd + b.(λ + d + c + cd)
= λ + d + c + cd + b + bd + bc + bcd
P(abcd) = λ + d + c + cd + b + bd + bc + bcd
+ aλ + ad + ac + acd + ab + abd + abc + abcd
If loops were allowed, then P is out power-set function. Otherwise, we would need a one-parameter loopless function for concatenating a given character to a given set of strings (which obviously are two things).
Some tweak could be possible by playing with String.replace (if a String result is desired, or by replacing Set with List (so that the "additional" parameter is actually the first element in the list).
This will also do the trick:
var powerset = function(arr, prefix, subsets) {
subsets = subsets || [];
prefix = prefix || [];
if (arr.length) {
powerset(arr.slice(1), prefix.concat(arr[0]), subsets);
powerset(arr.slice(1), prefix, subsets);
} else {
subsets.push(prefix);
}
return subsets;
};
powerset('abc');
Well if you don't have loops, emulate one with recursion, using iterators this is acutally quite simple.
public final Set<Set<Integer>> powerSet(Set<Integer> set) {
Set<Set<Integer>> powerSet = new HashSet<>();
powerSet(set, powerSet, set.iterator());
return powerSet;
}
public final void powerSet(Set<Integer> set, Set<Set<Integer>> powerSet, Iterator<Integer> iterator) {
if(iterator.hasNext()) {
Integer exlude = iterator.next();
Set<Integer> powThis = new HashSet<Integer>();
powThis.addAll(set);
powThis.remove(exlude);
powerSet.add(powThis);
powerSet(powThis, powerSet, powThis.iterator());
powerSet(set, powerSet, iterator);
}
}
//usage
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(3);
set.add(4);
log.error(powerSet(set).toString());
A recursive version of the generic solution proposed by João Silva :
public static <T> Set<Set<T>> powerSet2(Set<T> originalSet) {
Set<Set<T>> sets = new HashSet<Set<T>>();
if (originalSet.isEmpty()) {
sets.add(new HashSet<T>());
return sets;
}
List<T> list = new ArrayList<T>(originalSet);
T head = list.get(0);
Set<T> rest = new HashSet<T>(list.subList(1, list.size()));
addSets(sets, powerSet(rest), head);
return sets;
}
private static <T> void addSets(Set<Set<T>> sets, Set<Set<T>> setsToAdd, T head) {
Iterator<Set<T>> iterator = setsToAdd.iterator();
if (iterator.hasNext()) {
Set<T> set = iterator.next();
iterator.remove();
Set<T> newSet = new HashSet<T>();
newSet.add(head);
newSet.addAll(set);
sets.add(newSet);
sets.add(set);
addSets(sets, setsToAdd, head);
}
}
I extract the recursive addSets method to transform the original for loop:
for (Set<T> set : powerSet(rest)) {
Set<T> newSet = new HashSet<T>();
newSet.add(head);
newSet.addAll(set);
sets.add(newSet);
sets.add(set);
}
void powerSet(int * ar, int *temp, int n, int level,int index)
{
if(index==n) return;
int i,j;
for(i=index;i<n;i++)
{
temp[level]=ar[i];
for(j=0;j<=level;j++)
printf("%d ",temp[j]);
printf(" - - - t\n");
powerSet(ar, temp, n, level+1,i+1);
}
}
int main()
{
int price[] = {1,2,3,7};
int temp[4] ={0};
int n = sizeof(price)/sizeof(price[0]);
powerSet(price, temp, n, 0,0);
return 0;
}
Simple solution but with poor time complexity(2^n) is as following(just keep one thing in mind once we have to avoid(i.e. 0) and once we have to take it(i.e. 1):
public HashSet<int[]> powerSet(int n) {
return calcPowerSet(n-1, new HashSet<int[]>(), new int[n]);
}
private HashSet<int[]> calcPowerSet(int n, HashSet<int[]> result, int []set) {
if(n < 0) {
result.add(set.clone());
return null;
}
else {
set[n] = 0;
calcPowerSet(n-1, result, set);
set[n] = 1;
calcPowerSet(n-1, result, set);
return result;
}
}
Just for fun, a version that does powersets of any set stored in a LinkedList (to make it easy to remove the head element). Java 8 streams do the functional part:
static <T> LinkedList<LinkedList<T>> powerset(LinkedList<T> elements) {
if (elements.isEmpty())
return copyWithAddedElement(new LinkedList<>(), new LinkedList<>());
T first = elements.pop();
LinkedList<LinkedList<T>> powersetOfRest = powerset(elements);
return Stream.concat(
powersetOfRest.stream(),
powersetOfRest.stream().map(list -> copyWithAddedElement(list, first)))
.collect(Collectors.toCollection(LinkedList::new));
}
static <T> LinkedList<T> copyWithAddedElement(LinkedList<T> list, T elt) {
list = new LinkedList<>(list);
list.push(elt);
return list;
}
This is inspired by the following Common Lisp, which shows that the right language can make things simpler:
(defun powerset (set)
(cond ((null set) '(()))
(t (let ((powerset-of-rest (powerset (cdr set))))
(append powerset-of-rest
(mapcar #'(lambda (x) (cons (car set) x))
powerset-of-rest))))))
Based on the info here, here is solution in C#.
NOTE: the loop in the main function is just to print the result into the console value. No loops used in the PowerSet method.
public static void Main(string[] args)
{
string input = "abbcdd";
Dictionary < string, string> resultSet = new Dictionary<string, string>();
PowerSet(input, "", 0, resultSet);
//apply sorting
var resultSorted = resultSet.OrderBy(l => l.Key.Length).ThenBy(l=>l.Key);
//print values
foreach(var keyValue in resultSorted)
{
Console.Write("{{{0}}}, ",keyValue.Key);
}
}
/// <summary>
/// Computes the powerset of a string recursively
/// based on the Algorithm http://www.ideserve.co.in/learn/generate-all-subsets-of-a-set-recursion
/// </summary>
/// <param name="input">Original input string</param>
/// <param name="temp">Temporary variable to store the current char for the curr call</param>
/// <param name="depth">The character position we are evaluating to add to the set</param>
/// <param name="resultSet">A hash list to store the result</param>
public static void PowerSet(string input, string temp, int depth, Dictionary<string, string> resultSet)
{
//base case
if(input.Length == depth)
{
//remove duplicate characters
string key = new string(temp.ToCharArray().Distinct().ToArray());
//if the character/combination is already in the result, skip it
if (!resultSet.ContainsKey(key))
resultSet.Add(key, key);
return;//exit
}
//left
PowerSet(input, temp, depth + 1, resultSet);
//right
PowerSet(input, temp + input[depth], depth + 1, resultSet);
}
PowerSet will print all combinations of elements
for example [123] will forms 123,12,13,23,1,2,3
We can find the powerset values easily by using the concept of tree
let add an element or remove an element every time
abc
a " "
ab a b " "
abc ab ac a bc b c " "
here first have added a and not added a so tree form "a" and " " subelements
now take a constant and add 'b' to it and don't add 'b' then it will create another sub tree for 'a' in the same way the we add and remove element utill we reach the end .
here the method to add element and to remove element
powerset(str,i+1,cur+str.charAt(i));
powerset(str,i+1,cur);
import java.io.*;
import java.util.*;
import java.lang.Math;
class Demo{
public static void main(String args[]) {
String str="123";
String str1="";
int r=0;
powerset(str,r,str1);
}
public static void powerset(String str,int i,String cur){
if(i==str.length()){
System.out.println(cur);
return;
}
powerset(str,i+1,cur+str.charAt(i));
powerset(str,i+1,cur);
}
}
Power set (P) of string "abc" contains 2 types of elements: character 'a' itself and its combination with elements of P('bc').
Similarly P('bc') contains character 'b' and its combination with elements of P('c').
And also P('c') contains character 'c' and its combination with null string.
Now make function powerSet(string input, string substring="") This will print the substring and it denotes the combination of first element of input string with substring.
Base Condition: When length of input string is 0 then prints the substring.
Recursive condition:
1). Call powerSet( input[1: input.length()], substring ) #this is for elements of power set of string exluding 0th index character
2). Call powerSet( input[1: input.length()], substring+input[0]) # this is for combination.
#include<iostream>
#include<string>
using namespace std;
void powerSet(string input,string substring){
if(input.length()==0){
cout<<substring<<", ";
return;
}
string op1=substring;
string op2=substring + input[0];
powerSet(input.substr(1),op1);
powerSet(input.substr(1),op2);
return;
}
int main(){
string input="abc";
powerSet(input);
}
Related
I implemented an experimental OOP language and now benchmark garbage collection using a Storage benchmark. Now I want to check/print the following benchmark for small depths (n=2, 3, 4,..).
The tree (forest with 4 subnode) is generated by the buildTreeDepth method. The code is as follows:
import java.util.Arrays;
public final class StorageSimple {
private int count;
private int seed = 74755;
public int randomNext() {
seed = ((seed * 1309) + 13849) & 65535;
return seed;
}
private Object buildTreeDepth(final int depth) {
count++;
if (depth == 1) {
return new Object[randomNext() % 10 + 1];
} else {
Object[] arr = new Object[4];
Arrays.setAll(arr, v -> buildTreeDepth(depth - 1));
return arr;
}
}
public Object benchmark() {
count = 0;
buildTreeDepth(7);
return count;
}
public boolean verifyResult(final Object result) {
return 5461 == (int) result;
}
public static void main(String[] args) {
StorageSimple store = new StorageSimple();
System.out.println("Result: " + store.verifyResult(store.benchmark()));
}
}
Is there a somewhat simple/straight forward way to print the tree generated by buildTreeDepth? Just the short trees of n=3, 4, 5.
As other has already suggested, you may choose some lib to do so. But if you just want a simple algo to test in command line, you may do the following, which I always use when printing tree in command line (write by handle, may have some bug. Believe you can get what this BFS algo works):
queue.add(root);
queue.add(empty);
int count = 1;
while (queue.size() != 1) {
Node poll = queue.poll();
if (poll == empty) {
count = 1;
queue.add(empty);
}
for (Node n : poll.getChildNodes()) {
n.setNodeName(poll.getNodeName(), count++);
queue.add(n);
}
System.out.println(poll.getNodeName());
}
Sample output:
1
1-1 1-2 1-3 1-4
1-1-1 1-1-2 1-1-3 1-2-1 1-2-2 1-3-1 1-3-2 1-4-1
...
And in your case you use array, which seems even easier to print.
Instead of using object arrays, use a List implementation like ArrayList. For an improved better result subclass ArrayList to also hold a 'level' value and add indentation to the toString() method.
I have a array list contains thousands of data.
For Example:
List<String> custNames = new ArrayList<String>();
custNames.add("John");
custNames.add("Tom");
custNames.add("Bart");
custNames.add("Tim");
custNames.add("Broad");
Now I want to get count of names only starting with 'T'. I used looping mechanism for my solution.
List<String> filterNames = new ArrayList<String>();
String nameStarts="T";
for(int i=0;i<custNames.size();i++)
{
if(custNames.get(i).toLowerCase().startsWith(nameStarts.toLowerCase()))
{
filterNames.add(custNames.get(i));
}
}
System.out.println(filterNames.size());
But I have very large collection of data in this custNames list.
Is there any different solution without using loop?
Thanks.
There is very good solution from Java 8 for your problem.
Try this,
long filterNameCount = custNames
.stream()
.parallel()
.filter((s) -> s.startsWith(nameStarts.toLowerCase()))
.count();
System.out.println(filterNameCount);
If you are open to using a third-party library, there are a few interesting options you could use with Eclipse Collections.
If you use the ArrayList as you have it above, you can use the LazyIterate utility as follows:
int count = LazyIterate.collect(custNames, String::toLowerCase)
.countWith(String::startsWith, nameStarts.toLowerCase());
Assert.assertEquals(2, count);
If you use the Eclipse Collections replacement for ArrayList, you can use the rich functional protocols available directly on MutableList:
MutableList<String> custNames =
Lists.mutable.with("John", "Tom", "Bart", "Tim", "Broad");
String nameStarts= "T";
int count = custNames.asLazy()
.collect(String::toLowerCase)
.countWith(String::startsWith, nameStarts.toLowerCase());
System.out.println(count);
Assert.assertEquals(2, count);
The serial API in Eclipse Collections is eager-by-default, which is why I called asLazy() first. The collect method would otherwise create another MutableList.
If you benchmark your code with your full set of data, the following parallel version of the code may be more performant:
MutableList<String> custNames =
Lists.mutable.with("John", "Tom", "Bart", "Tim", "Broad");
String nameStarts= "T";
int processors = Runtime.getRuntime().availableProcessors();
int batchSize = Math.max(1, custNames.size() / processors);
ExecutorService executor = Executors.newFixedThreadPool(processors);
int count = custNames.asParallel(executor, batchSize)
.collect(String::toLowerCase)
.countWith(String::startsWith, nameStarts.toLowerCase());
executor.shutdown();
Assert.assertEquals(2, count);
The asParallel() API in Eclipse Collections is lazy-by-default. The API forces you to pass in a an ExecutorService and an int batchSize. This gives you complete control over the parallelism.
You can also use the Stream API with all MutableCollections in Eclipse Collections because they extend java.util.Collection.
Note: I am a committer for Eclipse Collections.
You could also use a tree storage : it would very efficient for this kind of search. If you are stucked with a list the previous answered is a way to do.
remove all the items which dont start with "T" like this:
custNames.removeIf(p->!p.startsWith("T"));
you can make a copy out of your list and remove items not starting with "T".
First, you can shorten your initialization with Arrays.asList(T); Second, I would use a simple loop to build a table of counts once and then use that to determine the subsequent queries. Something like,
List<String> custNames = new ArrayList<String>(Arrays.asList("John", "Tom",
"Bart", "Tim", "Broad"));
int[] counts = new int[26];
for (String name : custNames) {
char ch = Character.toLowerCase(name.charAt(0));
counts[ch - 'a']++;
}
for (int i = 0; i < counts.length; i++) {
if (counts[i] > 0) {
System.out.printf("There are %d words that start with %c%n",
counts[i], (char) ('a' + i));
}
}
Which outputs
There are 2 words that start with b
There are 1 words that start with j
There are 2 words that start with t
Or, in the specific case - counts['t' - 'a'] is the count of words starting with t.
If you have more or less static list and perform search operation often you can sort your list or use TreeMap.
Also you don't need to create new list and get its size then. You can simply create a counter variable and increment it.
You can create your own sorting and finding implementation.
Consider the following:
public class ContainingArrayList<E> extends ArrayList<E> {
private Comparator<E> comparator;
public ContainingArrayList(Comparator<E> comparator) {
this.setComparator(comparator);
}
#Override
public boolean add(E e) {
// If the collection is empty or the new element is bigger than the last one, append it to the end of the collection
if(size() == 0 || comparator.compare(e, get(size()-1)) >= 0)
return super.add(e);
else {
for (int i = 0; i < size(); i++) {
int result = comparator.compare(e, get(i));
// If the new element is bigger than the current element, continue with the next element
if (result > 0) continue;
// If the new element is equal to the current element, no need to insert (you might insert of course)
if (result == 0) return false;
// Otherwise the new element is smaller than the current element, so insert it between the previous and the current element
super.add(i, e);
return true;
}
return super.add(e);
}
}
public E get(E containingElement) {
int start = 0;
int end = size()-1;
// If the element is the first one, return the first element
if(comparator.compare(containingElement, super.get(start)) == 0)
return super.get(start);
// If the element is the last one, return the last element
if(comparator.compare(containingElement, super.get(end)) == 0)
return super.get(end);
// Otherwise do a binary search
while(start != end) {
// Get the element between start and end positions
E mid = super.get(start + (end/2));
// Compare the two elements
int result = comparator.compare(containingElement, mid);
// If the middle element compared to the containing element is equal, return the middle element
if(result == 0) {
return mid;
}
// If the containing element is smaller than the middle, halve the end position
else if(result < 0) {
end = start + (end/2);
}
// If the containing element is bigger than the middle, set the start position to the middle position
else if(result > 0) {
start = start + (end/2);
}
}
return null;
}
public Comparator<E> getComparator() {
return comparator;
}
public void setComparator(Comparator<E> comparator) {
this.comparator = comparator;
}
}
The custom comparator is used to sort the elements and to find the element that starts with a specific character. This means that you can change the comparator implementation for your needs at any time or you can create a more dynamic finding solution.
Test:
public class SortFindTest {
public SortFindTest() {
ContainingArrayList<String> t = new ContainingArrayList<String>(new MyComparator());
t.add("John");
t.add("Tom");
t.add("Bart");
t.add("Tim");
t.add("Broad");
System.out.println(t.get("T"));
}
class MyComparator implements Comparator<String> {
#Override
public int compare(String o1, String o2) {
int o1c = o1.charAt(0);
int o2c = o2.charAt(0);
if(o1c == o2c)
return 0;
if(o1c > o2c)
return 1;
return -1;
}
}
public static void main(String[] args) {
new SortFindTest();
}
}
I'm not sure if this would be faster than Java 8 Stream API but it worth a try.
If the order in which the items are stored does not matter, you could store the names in a HashMap, where the first character of each name is the key, and an ArrayList of names with that first character are the values. And then all you need to do, assuming the HashMap is named customerList, is customerList.get("T").size().
Initializing HashList and Adding Customers
HashMap<Character, ArrayList<String>> customerList = new HashMap<Character, ArrayList<String>>();
int NUM_ALPHABETS = 26;
int ascii_char = 97;
for(int i = 0; i < NUM_ALPHABETS; i++){
char c = (char) ascii_char;
customerList.add(c, new ArrayList<String>());
ascii_char++;
}
customerList.get("t").add("Tony");
customerList.get("a").add("Alice");
customerList.get("b").add("Ben");
Getting Number of Customers Starting with "t"
int num_t = customerList.get("t").size();
Hi In this recursion method i am trying to find all anagrams and add it to a List> but what happens when i run this code is it just returns alot of empty Lists.
private List<List<String>> findAnagrams(LetterInventory words,
ArrayList<String> anagram, int max,
Map<String, LetterInventory> smallDict, int level, List<List<String>> result) {
ArrayList<String> solvedWord = new ArrayList<String>();
LetterInventory shell;
LetterInventory shell2;
if (level < max || max == 0) {
Iterator<String> it = smallDict.keySet().iterator();
while (it.hasNext()) {
String k = it.next();
shell = new LetterInventory(k);
shell2 = words;
if (shell2.subtract(shell) != null) {
anagram.add(k);
shell2 = words.subtract(shell);
if (shell2.isEmpty()) {
//System.out.println(anagram.toString()); it prints off fine here
result.add(anagram); // but doesnt add here
}
else
findAnagrams(shell2, anagram, max, smallDict, level + 1, result);
anagram.remove(anagram.size()-1);
}
}
}
return results;
}
My guess is it's here.
else
findAnagrams(shell2, anagram, max, smallDict, level + 1, result);
anagram.remove(anagram.size()-1); // this is outside of the else case
You remove an element from anagram every time you add it. Did you mean to for it to be in the else?
else {
findAnagrams(shell2, anagram, max, smallDict, level + 1, result);
anagram.remove(anagram.size()-1);
}
I'm using an ArrayList to hold a history of objects. Each new object I add using the .add method, like:
if(event.getAction() == MotionEvent.ACTION_UP)
{
if(currentWord != null)
{
wordHist.add(currentWord);
}
if(wordHist.size() > WORDHIST_MAX_COUNT)
{
wordHist.remove(0);
}
}
However I don't want this to grow indefinitely, but to be limited to a certain value. If it reaches this maximum value, I want the oldest object (index 0) to be removed, and the rest to be left shifted, so previous index 1 is now index 0, etc.
How can this be done?
Thanks
ArrayList is not really a good choice in this case, but it can by done by calling remove(0) method. But if you want to do that efficiently, a linked list is better
(edited to make it clear that LinkedList is not generally better than ArrayList, but only in this case)
If it reaches this maximum value, I want the oldest object (index 0) to be removed
Then do wordHist.remove(0). That will remove the element at index 0.
To be precise:
wordHist.add(new Word("hello"));
if (wordHist.size() > MAX_SIZE)
wordHist.remove(0);
As user658991 states however, you should be aware of that this is a linear operation, i.e., takes time proportional to the number of elements in the list.
You could do this in constant time using LinkedList methods add and removeFirst.
Another option would be to wrap an array, or ArrayList in a class called something like CircularArrayList. In circular list structures you'll override the oldest element when adding a new one.
Edit:
Your code works fine:
import java.util.*;
class Test {
static int WORDHIST_MAX_COUNT = 3;
static List<String> wordHist = new ArrayList<String>();
public static void add(String currentWord) {
// VERBATIM COPY OF YOUR CODE
if (true/*event.getAction() == MotionEvent.ACTION_UP*/)
{
if(currentWord != null)
{
wordHist.add(currentWord);
}
if(wordHist.size() > WORDHIST_MAX_COUNT)
{
wordHist.remove(0);
}
}
}
public static void main(String[] args) {
add("a");
add("b");
add("c");
for (int i = 0; i < wordHist.size(); i++)
System.out.printf("i: %d, word: %s%n", i, wordHist.get(i));
System.out.println();
add("d");
for (int i = 0; i < wordHist.size(); i++)
System.out.printf("i: %d, word: %s%n", i, wordHist.get(i));
}
}
Prints:
i: 0, word: a
i: 1, word: b
i: 2, word: c
i: 0, word: b <-- b is now at index 0.
i: 1, word: c
i: 2, word: d
Use the remove( ) method.
Using remove(0) will remove the element from the 0th index.
U can use list.remove(index)// here index being '0', this internally shifts rest of the array up. An alternative solution wud be to use a queue or dequeue.
One simple implementation of what Op De Cirkel suggested
import java.util.ArrayList;
import java.util.List;
public class SimpleCircularHistory {
private int sizeLimit, start = 0, end = 0;
boolean empty = false;
private List<String> history;
public SimpleCircularHistory(int sizeLimit) {
this.sizeLimit = sizeLimit;
history = new ArrayList<String>(sizeLimit);
}
public void add(String state){
empty = false;
end = (end + 1) % sizeLimit;
if(history.size() < sizeLimit){
history.add(state);
}else {
history.set(end, state);
start = (end + 1) % sizeLimit;
}
}
public String rollBack(){
if(empty){ // Empty
return null;
}else {
String state = history.get(end);
if(start == end){
empty = true;
}else {
end = (end + sizeLimit - 1) % sizeLimit;
}
return state;
}
}
public void print(){
if(empty){
System.out.println("Empty");
}else {
for(int i = start;; i = (i + 1) % sizeLimit){
System.out.println(history.get(i));
if(i == end) break;
}
System.out.println();
}
}
public static void main(String[] args) {
SimpleCircularHistory h = new SimpleCircularHistory(3);
h.add("a");
h.add("b");
h.add("c");
h.add("d");
h.add("e");
h.add("f");
h.print();
h.add("X");
h.add("Y");
h.rollBack();
h.rollBack();
h.print();
h.add("t");
h.add("v");
h.add("w");
h.print();
h.rollBack();
h.rollBack();
h.rollBack();
h.print();
h.rollBack();
h.print();
}
}
This would print out :
d
e
f
f
t
v
w
Empty
Empty
Yeah, I've noticed this behaviour in adroid's lists too. It's REALLY irritating.
Anyway, there is a way to get around it if I don't mind object creation/destruction and the resulting garbage collection (NEVER do this in a onDraw of a surfaceview or something).
What I do is basically have two tracking int's; one to place the new object, and one to remove it:
int trackInt = 0;
int removeInt = 0;
//and then, in the method/class you use this:
Object newobject = new Object();
//add to list
objectList.add(trackInt, newobject);
trackInt++;
if (bugList.size() > 20) //20 is the max number of object you want, ie the maximum size of the list
{
objectList.remove(removeInt);
trackInt = removeInt;
removeInt++;
if (removeInt > 19) //remember, the list is zero indexed!
{
removeInt = 0;
}
}
Commons-collections has exactly what you're looking for:
http://commons.apache.org/collections/apidocs/org/apache/commons/collections/buffer/CircularFifoBuffer.html
I have written a generic Partition class (a partition is a division of a set into disjoint subsets, called parts). Internally this is a Map<T,Integer> and a Map<Integer,Set<T>>, where the Integers are the labels of the parts. For example partition.getLabel(T t) gives the label of the part that t is in, and partition.move(T t, Integer label) moves t to the partition labelled by label (internally, it updates both the Maps).
But my method for moving a Collection of objects to a new part does not work. It seems that Set.removeAll() is affecting its argument. I think the problem is something like a ConcurrentModificationException, but I can't work it out. Sorry the code is rather long, but I have marked where the problem is (about half-way down), and the output at the bottom should make it clear what the problem is - at the end the partition is in an illegal state.
import java.util.*;
public class Partition<T> {
private Map<T,Integer> objToLabel = new HashMap<T,Integer>();
private Map<Integer,Set<T>> labelToObjs =
new HashMap<Integer,Set<T>>();
private List<Integer> unusedLabels;
private int size; // = number of elements
public Partition(Collection<T> objects) {
size = objects.size();
unusedLabels = new ArrayList<Integer>();
for (int i = 1; i < size; i++)
unusedLabels.add(i);
// Put all the objects in part 0.
Set<T> part = new HashSet<T>(objects);
for (T t : objects)
objToLabel.put(t,0);
labelToObjs.put(0,part);
}
public Integer getLabel(T t) {
return objToLabel.get(t);
}
public Set<T> getPart(Integer label) {
return labelToObjs.get(label);
}
public Set<T> getPart(T t) {
return getPart(getLabel(t));
}
public Integer newPart(T t) {
// Move t to a new part.
Integer newLabel = unusedLabels.remove(0);
labelToObjs.put(newLabel,new HashSet<T>());
move(t, newLabel);
return newLabel;
}
public Integer newPart(Collection<T> things) {
// Move things to a new part. (This assumes that
// they are all in the same part to start with.)
Integer newLabel = unusedLabels.remove(0);
labelToObjs.put(newLabel,new HashSet<T>());
moveAll(things, newLabel);
return newLabel;
}
public void move(T t, Integer label) {
// Move t to the part "label".
Integer oldLabel = getLabel(t);
getPart(oldLabel).remove(t);
if (getPart(oldLabel).isEmpty()) // if the old part is
labelToObjs.remove(oldLabel); // empty, remove it
getPart(label).add(t);
objToLabel.put(t,label);
}
public void moveAll(Collection<T> things, Integer label) {
// Move all the things from their current part to label.
// (This assumes all the things are in the same part.)
if (things.size()==0) return;
T arbitraryThing = new ArrayList<T>(things).get(0);
Set<T> oldPart = getPart(arbitraryThing);
// THIS IS WHERE IT SEEMS TO GO WRONG //////////////////////////
System.out.println(" oldPart = " + oldPart);
System.out.println(" things = " + things);
System.out.println("Now doing oldPart.removeAll(things) ...");
oldPart.removeAll(things);
System.out.println(" oldPart = " + oldPart);
System.out.println(" things = " + things);
if (oldPart.isEmpty())
labelToObjs.remove(objToLabel.get(arbitraryThing));
for (T t : things)
objToLabel.put(t,label);
getPart(label).addAll(things);
}
public String toString() {
StringBuilder result = new StringBuilder();
result.append("\nPARTITION OF " + size + " ELEMENTS INTO " +
labelToObjs.size() + " PART");
result.append((labelToObjs.size()==1 ? "" : "S") + "\n");
for (Map.Entry<Integer,Set<T>> mapEntry :
labelToObjs.entrySet()) {
result.append("PART " + mapEntry.getKey() + ": ");
result.append(mapEntry.getValue() + "\n");
}
return result.toString();
}
public static void main(String[] args) {
List<String> strings =
Arrays.asList("zero one two three".split(" "));
Partition<String> p = new Partition<String>(strings);
p.newPart(strings.get(3)); // move "three" to a new part
System.out.println(p);
System.out.println("Now moving all of three's part to the " +
"same part as zero.\n");
Collection<String> oldPart = p.getPart(strings.get(3));
//oldPart = Arrays.asList(new String[]{"three"}); // works fine!
p.moveAll(oldPart, p.getLabel(strings.get(0)));
System.out.println(p);
}
}
/* OUTPUT
PARTITION OF 4 ELEMENTS INTO 2 PARTS
PART 0: [two, one, zero]
PART 1: [three]
Now moving all of three's part to the same part as zero.
oldPart = [three]
things = [three]
Now doing oldPart.removeAll(things) ...
oldPart = []
things = []
PARTITION OF 4 ELEMENTS INTO 1 PART
PART 0: [two, one, zero]
*/
Using my debugger I place a breakpoint before the removeAll and I can see (as I suspected) that oldPart and things as the same collection so removing all elements clears that collection.
Your code is extremely confusing but as far as I can work out, oldPart and things are actually the same object. Set.removeAll() certainly doesn't affect its argument unless it is the same object as it's invoked on:
public boolean removeAll(Collection<?> c) {
boolean modified = false;
if (size() > c.size()) {
for (Iterator<?> i = c.iterator(); i.hasNext(); )
modified |= remove(i.next());
} else {
for (Iterator<?> i = iterator(); i.hasNext(); ) {
if (c.contains(i.next())) {
i.remove();
modified = true;
}
}
}
return modified;
}
Update:
The easy way to eliminate this is to use a copy of things in the moveAll() method. Indeed such a copy already exists.
T arbitraryThing = new ArrayList<T>(things).get(0);
This line creates but then instantly discards a copy of things. So I'd suggest replacing it with:
ArrayList<T> thingsToRemove = new ArrayList<T>(things)
T arbitraryThing = thingsToRemove.get(0);
And in the rest of the method, replace all references to things to thingsToRemove.