There is a 2d array with contains set and I want to put it on a map as key. Please, someone, suggest how to do it correctly. Expected and actual outputs are attached below.
public class trysome
{
static int[][] points = {{1,2}, {1,1},{5,7}};
public static void some()
{
HashMap<int[], Integer> map= new HashMap<int[], Integer>();
for(int i =0;i<points.length;i++)
{
map.put(points[i], 1);
}
for(Entry<int[], Integer> entry : map.entrySet())
{
System.out.println(entry.getKey() + " "+entry.getValue());
}
}
public static void main(String[] args)
{
trysome.some();
}
}
Actual Output:
[I#16b4a017 1
[I#8807e25 1
[I#2a3046da 1
Expected Output:
{1,2} 1
{1,1} 1
{5,7} 1
The reason for the output that you are observing is explained in What's the simplest way to print a Java array?. The bottom line is: The output [I#16b4a017 is basically the "memory location" of the array, and just not the contents of the array.
The reason why I'm not closing this as a duplicate is that the output here is just an irrelevant symptom of a much greater flaw: Your approach is conceptually wrong.
You cannot use an int[] array as the key in a hash-based datastructure!
One might argue that it would work if one relied on the identity of the arrays. But that's rarely the case.
The reason for that is that the equals and hashCode methods are not implemented on arrays in the way that would be necessary for this to work. Omitting some technical details that can be read elsewhere.
If your code is supposed to handle 2D points in a plane, then you should use a proper class to represent these points. This class could then include proper implementations of hashCode, equals and toString.
Fortunately, there already is such a class in the Java standard API, namely, java.awt.Point.
The following shows why your original implementation would not work as expected, in the usingArraysAsKeys method, and how it could be implemented properly in the usingPointsAsKeys method:
import java.awt.Point;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class PointsAsKeys
{
public static void main(String[] args)
{
usingArraysAsKeys();
usingPointsAsKeys();
}
public static void usingPointsAsKeys()
{
Point points[] =
{
new Point(1, 2),
new Point(1, 1),
new Point(5, 7)
};
Map<Point, Integer> map = new HashMap<Point, Integer>();
for (int i = 0; i < points.length; i++)
{
map.put(points[i], 1);
}
for (Entry<Point, Integer> entry : map.entrySet())
{
Point p = entry.getKey();
String s = "{" + p.x + ", " + p.y + "}";
System.out.println(s + " " + entry.getValue());
}
//=====================================================================
// Important: This shows that it WILL work as expected!
Point somePoint = new Point(1, 2);
Integer value = map.get(somePoint);
System.out.println("Value for " + somePoint + " is " + value);
}
public static void usingArraysAsKeys()
{
int[][] points =
{
{ 1, 2 },
{ 1, 1 },
{ 5, 7 }
};
HashMap<int[], Integer> map = new HashMap<int[], Integer>();
for (int i = 0; i < points.length; i++)
{
map.put(points[i], 1);
}
for (Entry<int[], Integer> entry : map.entrySet())
{
// This would print the arrays as "[I#139a55"
//System.out.println(entry.getKey() + " " + entry.getValue());
// This will print the arrays as [1, 2]:
System.out.println(
Arrays.toString(entry.getKey()) + " " + entry.getValue());
}
//=====================================================================
// Important: This shows that it will NOT work as expected!
int somePoint[] = { 1, 2 };
Integer value = map.get(somePoint);
System.out.println(
"Value for " + Arrays.toString(somePoint) + " is " + value);
}
}
Another advantage of using the Point class is that it already has several convenient methods - most importantly, a Point2D#distance method that allows you to compute the distance of a point to another one:
// Computes the distance of the point to the point at (0,0) (i.e. the origin)
double distanceToOrigin = point.distance(new Point(0,0));
(By the way: If the map is supposed to store distances, then its value type should probably be Double and not Integer)
Try this:
System.out.println(Arrays.toString(entry.getKey()) + " "+entry.getValue());
Output (for example):
[1, 2] 1
Or if you want to exact as Expected Output:
System.out.println(String.format("{%d,%d}", entry.getKey()[0], entry.getKey()[1]) +
" " + entry.getValue());
This method can help you:
private static String intArrayToString(int[] inputArray) {
StringBuilder output = new StringBuilder().append('{');
for (int i = 0; i < inputArray.length - 1; i++) {
output.append(inputArray[i]);
output.append(',');
}
output.append(inputArray[inputArray.length - 1]);
return output.append('}').toString();
}
}
You can use it like this:
System.out.println(intArrayToString(entry.getKey()) + " " + entry.getValue());
Benefits of this solution are that you can customize it as you wish.
Related
I have the following code (with some sample data), and wished to check whether there is any better or performant way to compare each element of the list of map to the subsequent one:
import java.util.*;
public class CompareElements {
private static List<Map<String, String>> sample = new ArrayList<>(0);
private static int MIN = 0;
private static int MAX = 10;
static {
populateListOfMaps();
}
/*
* This is the main part of the question, rest is just to generate test data..
*/
public static void main(String[] args){
// Can we simplify this part using lambda's or any library?
for (int i = 0; i < sample.size() -1; i++) {
for (int j = i+1; j < sample.size(); j++) {
Map<String, String> referenceMap = sample.get(i);
Map<String, String> candideMap = sample.get(j);
if(referenceMap.get("key").equalsIgnoreCase(candideMap.get("key"))){
System.out.println("Equal : " + i + " || " + referenceMap.get("key") + " and "+ j + " || " + candideMap.get("key") + " are pairs");
} else {
System.out.println("Not equal : " + i + " || " + referenceMap.get("key") + " and "+ j + " || " + candideMap.get("key") + " are pairs");
}
}
}
}
private static void populateListOfMaps(){
if(sample.size() <= 10){
Map<String, String> someMap = new HashMap<>(0);
someMap.put("key", "value" + randInt(MIN, MAX));
sample.add(someMap);
populateListOfMaps();
}
}
public static int randInt(int min, int max) {
Random rand = new Random();
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
}
My requirement is to compare each element of the list of maps and then check for equality to remove duplicate, this is a simpler part, but each map in my real time application has 2 keys-values (but both are String.. no custom POJO object).
The above code works but I wish to make this more concise and performant code.
Can we use lambdas or streams?
As you are getting data from MongoDB, I assume you have no control over the schema, so using a POJO isn't a simple option. (it can be done with generated code, but you probably don't want to go there)
What you can do is using groupingBy to change this O(n^2) loops into O(n)
public static void main(String... args) {
List<Map<String, String>> sample = populateListOfMaps();
sample.stream()
.collect(Collectors.groupingBy(m -> m.get("key")))
.forEach((key, list) -> System.out.println(key + " : " + list));
}
private static List<Map<String, String>> populateListOfMaps() {
Random rand = new Random();
return IntStream.range(0, 10)
.mapToObj(i -> {
Map<String, String> someMap = new HashMap<>(2);
someMap.put("key", "value-" + rand.nextInt(10));
return someMap;
})
.collect(Collectors.toList());
}
This will print all the entries which have the same "key" value with O(n) time complexity. e.g.
value-9 : [{key=value-9}]
value-8 : [{key=value-8}, {key=value-8}, {key=value-8}]
value-5 : [{key=value-5}]
value-7 : [{key=value-7}, {key=value-7}]
value-1 : [{key=value-1}]
value-0 : [{key=value-0}]
value-2 : [{key=value-2}]
I'm not realy sure what your exact requirements are so to tackle your question one part at a time:
check whether there is any better or performant way to compare each element of the list of map to the subsequent one:
How about using keySets?
Set<String> s1 = new HashSet< String >(referenceMap.values());
Set<String> s2 = new HashSet< String >(candideMap.values());
// Get intersection of values
s1.retainAll(s2);
// You can also get corresponding keys for each value later
This should reduce your complexity from O(n^2) to O(n)
each map in my real time application has 2 keys-values (but both are String.. no custom POJO object).
Not sure what you mean by real-time. Are the maps changing in real time? Neither your solution nor mine would be thread safe.
Do you mean 2 keys-values for each entry? If you mean 2 values for each key, you would probably override the hashcode(), equals() and your code should work.
Let me know if I misunderstood your question
I have multiple int type variables and on specific condition any one of those variables got incremented. Now I have to know some data structure in java that i can do this thing without using multiple variables.
A portion of my code is here:
switch(diff)
{
case 4:
{
count4++;
break;
}
case 5:
{
count5++;
break;
}
case 6:
{
count6++;
break;
}
}
Conditions may be increased so it is not good approach to add variable for each new condition. Kindly let me know some other better approach or data structure which can solve my problem.
Edit 1:
I am extracting time difference between consucetive lines in log file. Actually in the end I need a summary like
Difference 3 sec = 10
Difference 4 sec = 5
For above purpose I am using counter variables for each time difference. I need to know about some other way to do this thing,
You could use a Map (e.g. HashMap) with the key representing the name of the variable and the map's value representing the variable's value. This allows for having a flexible data structure where it is not necessary to know in before how many "variables" there will be.
This is strange because of the names you gave to your variables, but you could use an array:
int[] counts = {0, 0, 0};
Then count4 is counts[0], count5 is counts[1] and count6 is counts[2] so you can do:
counts[diff - 4]++;
You can use a HashMap
Example:
public class Test
{
public static void main(String[] args)
{
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("counter5", 1);
map.put("counter4", 1);
map.put("counter2", 1);
map.put("counter1", 1);
int diff = 2;
compute(map, diff);
diff = 2;
compute(map, diff);
diff = 1;
compute(map, diff);
}
private static void compute(HashMap<String, Integer> map, int diff)
{
System.out.println("Before counter no: "+diff+" value "+map.get("counter" + diff));
Integer counter = map.get("counter" + diff);
map.put("counter" + diff, --counter);
System.out.println("After counter no: "+diff+" value "+map.get("counter" + diff));
System.out.println("");
}
}
As pzaenger you can do something like:
As you already know how many case are there so you can initialize an array with that much size. Like you have 10 case then you can initialize an int array of size 10 as:
int[] count = new int[10];
now suppose you have a case of 4, i.e. 4th index of int array but as index start from 0 so you can do
int[4-1] = int[4-1]++;
if you just want to keep track of the diff number you could do something like this.
Map<Integer, Integer> pathMap = new HashMap<Integer, Integer>();
public void testSaveEntries() {
for ( int i = 0; i < 10; i++) {
int value = i % 5;
increaseCounter(value);
}
}
private void increaseCounter(int i) {
Integer value = pathMap.get(i);
pathMap.put(i, value == null ? 1 : ++value);
}
Try This....
public static void main(String[] args) {
int[] aaa=new int[]{10,2,4,5,7,8,3,34,4,4,545,5,3,4,4,5,5,5,10,3,4,45,6,2,7};
Map<Integer, Integer> all_counts=new LinkedHashMap<Integer,Integer>();
for (int key : aaa) {
if(all_counts.containsKey(key))
{
Integer count=all_counts.get(key);
count++;
all_counts.put(key, count);
}
else
{
all_counts.put(key, 1);
}
}
for (Map.Entry<Integer, Integer> entry : all_counts.entrySet())
{
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
}
I have a list with HashMap<Integer, Point3d> format like in the following way.
{
{key1,(x1,y1,z1)},
{key2,(x2,y2,z2)},
{key3,(x1,y3,z3)},
{key4,(x1,y4,z4)},
{key5,(x5,y5,z5)},
..
}
First I want to seperate first elements from all the points like {x1,x2,x1,x1,x5} and then remove duplicates like {x1,x2,x5} finally length of the result means {x1,x2,x5}.size()
In the same way I want to implement for 2nd and 3rd elements of the Points.
I tried allot but I didn't find anyway.because we can't able to retrieve values from HashMap based on index. we can able to retrieve values based on Key value But I don't know the Keyvalues hashMap.
I tried in the following way.
public int xSideLength(HashMap<Integer, Point3d> coOrdinates) {
int length=0;
Set<Integer> keyValues=coOrdinates.keySet();
Integer[] array=(Integer[]) keyValues.toArray();
for (int index = 0; index < array.length; index++) {
//logical code
}
return length;
}
Can anyone suggest me.
What do you think of the following:
Set<Integer> values = new HashSet<Integer>();
for(Point3d point : coordinates.values()) {
values.add(point.x());
}
return values.size();
You can get elements from the map using the key like this:
Set<Integer> keyValues = coOrdinates.keySet();
for (Integer key : keyValues) {
Point3d point = coOrdinates.get(key);
// Your logical code goes here.
}
You can follow the following steps,
Put the values of the HashMap into a Set with your custom Comparator.
Implement your compare method.
Return the set size.
The snippet looks like below,
public int xSideLength(HashMap<Integer, Point3d> coOrdinates) {
int length=0;
Set<Point3d> values = new TreeSet<Point>(new Comparator<Point3d>() {
#Override
public int compare(Point3d e1, Point3d e2) {
return e1.getX().compareTo(e2.getX());
}
});
values.addAll(coOrdinates.values());
return values.size();
}
public static void zz() {
Map<String,Point3d> m = new HashMap<String,Point3d>();
m.put("k1", new Point3d(1.0, 1.0, 4.0));
m.put("k2", new Point3d(2.0, 2.0, 2.0));
m.put("k3", new Point3d(1.0, 3.0, 2.0));
m.put("k4", new Point3d(1.0, 3.0, 4.0));
m.put("k5", new Point3d(5.0, 3.0, 2.0));
Set xvals = new HashSet();
Set yvals = new HashSet();
Set zvals = new HashSet();
double[] coords = new double[3];
for (Point3d p : m.values()) {
p.get(coords);
xvals.add(coords[0]);
yvals.add(coords[1]);
zvals.add(coords[2]);
}
System.out.println("# unique x: " + xvals.size() + ": " + xvals);
System.out.println("# unique y: " + yvals.size() + ": " + yvals);
System.out.println("# unique z: " + zvals.size() + ": " + zvals);
}
for (Map.Entry<Integer, Point3d> entry : coOrdinates.entrySet()) {
Point3d point = entry.getValue());
}
In java, I want to compare two maps, like below, do we have existing API to do this ?
Thanks
Map<String, String> beforeMap ;
beforeMap.put("a", "1");
beforeMap.put("b", "2");
beforeMap.put("c", "3");
Map<String, String> afterMap ;
afterMap.put("a", "1");
afterMap.put("c", "333");
//--- it should give me:
b is missing, c value changed from '3' to '333'
I'd use removeAll() functionality of Set to to do set differences of keys to find additions and deletions. Actual changes can be detected by doing a set difference using the entry set as HashMap.Entry implements equals() using both key and value.
Set<String> removedKeys = new HashSet<String>(beforeMap.keySet());
removedKeys.removeAll(afterMap.keySet());
Set<String> addedKeys = new HashSet<String>(afterMap.keySet());
addedKeys.removeAll(beforeMap.keySet());
Set<Entry<String, String>> changedEntries = new HashSet<Entry<String, String>>(
afterMap.entrySet());
changedEntries.removeAll(beforeMap.entrySet());
System.out.println("added " + addedKeys);
System.out.println("removed " + removedKeys);
System.out.println("changed " + changedEntries);
Output
added []
removed [b]
changed [c=333]
The Guava Maps class has some methods for calulating the differences between a pair of maps. However, these methods give you a data structure representing the differences not a pretty-printed string.
There isn't any out of the box component to help with that. You'll probably have to code it unfortunately. The good news is the logic is pretty easy.
Depending upon your particular needs, you might also consider using other applications designed to do this work, like diff. You could write the two maps to two different files, and diff the files.
String output = new String();
for (String key:beforeMap.getKeys()){
String beforeValue = beforeMap.getValue(key);
String afterValue = afterMap.getValue(key);
//nullsafe
if(beforeValue.equals(afterValue){}
else if (afterValue == null){
output = output + key + " is missing, ";
continue;
}else {
output = output + key + " has changed from " + beforeValue + " to " + afterValue + " , ";
}
afterMap.remove(key);
}
for (String key:afterMap.getKeys()){
output = output + key + " was added with value " + afterMap.getValue(key) + ", ";
}
if(output == null){
output = "Same map";
}
output = output.substring(0,output.length-2);
System.out.println(output);
You could use a custom object that contains the key and the value (actually Map does this internally, hidden from the user, so we can't use that)
Put these tuples into a Set
To compare two sets, convert them both to arrays, sort the arrays and walk both arrays from begin to end in parallel, stepping down the first array if it's key is smaller than the key in the second array, and vise versa.
class Tuple implements Comparable<Tuple>
{
public String key;
public String value;
public Tuple(String key, String value)
{
this.key = key;
this.value = value;
}
#Override
public int compareTo(Tuple o)
{
return key.compareTo(o.key);
}
}
public static void main(String[] args)
{
// TreeSet is already sorted. If you use HashSet, use Arrays.sort()
Set<Tuple> beforeSet = new TreeSet<>();
beforeSet.add(new Tuple("a", "1"));
beforeSet.add(new Tuple("b", "2"));
beforeSet.add(new Tuple("c", "4"));
Set<Tuple> afterSet = new TreeSet<>();
afterSet.add(new Tuple("a", "1"));
afterSet.add(new Tuple("c", "333"));
afterSet.add(new Tuple("aa", "4"));
Tuple[] beforeArray = beforeSet.toArray(new Tuple[beforeSet.size()]);
Tuple[] afterArray = afterSet.toArray(new Tuple[afterSet.size()]);
int beforePtr = 0;
int afterPtr = 0;
while (beforePtr < beforeArray.length || afterPtr < afterArray.length)
{
int difference = afterPtr >= afterArray.length? -1 : beforePtr >= beforeArray.length? 1 : beforeArray[beforePtr].compareTo(afterArray[afterPtr]);
if (difference == 0)
{
if (!beforeArray[beforePtr].value.equals(afterArray[afterPtr].value))
{
System.out.println(beforeArray[beforePtr].key + " value changed from '" + beforeArray[beforePtr].value + "' to '" + afterArray[afterPtr].value + "'");
}
beforePtr++;
afterPtr++;
}
else if (difference < 0)
{
System.out.println(beforeArray[beforePtr].key + " is missing");
beforePtr++;
}
else
{
System.out.println(afterArray[afterPtr].key + " is added");
afterPtr++;
}
}
}
#user595234 To Compare the two Maps you can add the keys of a map to list and with those 2 lists you can use the methods retainAll() and removeAll() and add them to another common keys list and different keys list. Using the keys of the common list and different list you can iterate through map, using equals you can compare the maps.
public class Demo
{
public static void main(String[] args)
{
Map<String, String> beforeMap = new HashMap<String, String>();
beforeMap.put("a", "1");
beforeMap.put("b", "2");
beforeMap.put("c", "3");
Map<String, String> afterMap = new HashMap<String, String>();
afterMap.put("a", "1");
afterMap.put("c", "333");
System.out.println("Before "+beforeMap);
System.out.println("After "+afterMap);
List<String> beforeList = getAllKeys(beforeMap);
List<String> afterList = getAllKeys(afterMap);
List<String> commonList1 = beforeList;
List<String> commonList2 = afterList;
List<String> diffList1 = getAllKeys(beforeMap);
List<String> diffList2 = getAllKeys(afterMap);
commonList1.retainAll(afterList);
commonList2.retainAll(beforeList);
diffList1.removeAll(commonList1);
diffList2.removeAll(commonList2);
System.out.println("Common List of before map "+commonList1);
System.out.println("Common List of after map "+commonList2);
System.out.println("Diff List of before map "+diffList1);
System.out.println("Diff List of after map "+diffList2);
if(commonList1!=null & commonList2!=null) // athough both the size are same
{
for (int i = 0; i < commonList1.size(); i++)
{
if ((beforeMap.get(commonList1.get(i))).equals(afterMap.get(commonList1.get(i))))
{
System.out.println("Equal: Before- "+ beforeMap.get(commonList1.get(i))+" After- "+afterMap.get(commonList1.get(i)));
}
else
{
System.out.println("Unequal: Before- "+ beforeMap.get(commonList1.get(i))+" After- "+afterMap.get(commonList1.get(i)));
}
}
}
if (CollectionUtils.isNotEmpty(diffList1))
{
for (int i = 0; i < diffList1.size(); i++)
{
System.out.println("Values present only in before map: "+beforeMap.get(diffList1.get(i)));
}
}
if (CollectionUtils.isNotEmpty(diffList2))
{
for (int i = 0; i < diffList2.size(); i++)
{
System.out.println("Values present only in after map: "+afterMap.get(diffList2.get(i)));
}
}
}
/** getAllKeys API adds the keys of the map to a list */
private static List<String> getAllKeys(Map<String, String> map1)
{
List<String> key = new ArrayList<String>();
if (map1 != null)
{
Iterator<String> mapIterator = map1.keySet().iterator();
while (mapIterator.hasNext())
{
key.add(mapIterator.next());
}
}
return key;
}
}
The below code will give you this output:
Before: {b=2, c=3, a=1}
After: {c=333, a=1}
Unequal: Before- 3 After- 333
Equal: Before- 1 After- 1
Values present only in before map: 2
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.