Reliability of `TreeSet` for orderability - java

Is it reliable to use the following Java code:
TreeSet<String> ts = new TreeSet<String>();
String stringAtIndexThree = Arrays.<Tag> asList(list.toArray(new Tag[list.size()])).get(3);
to get the object at the third index (assuming that ts.size() > 3)?
That is, will TreeSet<T>#toArray(T[]) always return the elements in the same order, if no modifications are made to the set?
If it matters, this is for a ComboBoxModel implementation that should have only unique elements (optimally, I would use the non-existent UniqueList).
Thanks!
WC

will TreeSet#toArray(T[]) always return the elements in the same order, if no modifications are made to the set?
Absolutely - TreeSet returns elements in the same sorted order. Of course your elements should play nicely when it comes to implementing comparable in order for that sorting order to be what you expect.

Related

Java split string array by parameter

Let's say we have a string array like this:
{abc,abc,abc,def,def,ghi}
Is there a way to make a String array containing each possibility only once?
e.g. {abc,def,ghi}
I was thinking about iterating over an array, sorted beforehand, and checking if the previous elements equals the next one. If not add it to list and convert it to array later on if necessary.
But is there a simpler solution ?
By the way, since I am programming for android, I can't use any features of Java 8.
Simply copy the array into a Set:
Set<String> noDupes = new LinkedHashSet<>(Arrays.asList(yourArray));
By definition, Sets do not contain duplicates. You can use HashSet (or any other Set implementation) rather than LinkedHashSet, but LinkedHashSet preserves the order in which the elements first appear in the array.
Sure: iterate the array and push the values into a Set.
When using the LinkedHashSet, you even keep the initial order.
Or, without looping manually:
Set<String> = new LinkedHashSet<>(Arrays.asList(yourArray)) ;

Cull all duplicates in a set

I'm using Set to isolate the unique values of a List (in this case, I'm getting a set of points):
Set<PVector> pointSet = new LinkedHashSet<PVector>(listToCull);
This will return a set of unique points, but for every item in listToCull, I'd like to test the following: if there is a duplicate, cull all of the duplicate items. In other words, I want pointSet to represent the set of items in listToCull which are already unique (every item in pointSet had no duplicate in listToCull). Any ideas on how to implement?
EDIT - I think my first question needs more clarification. Below is some code which will execute what I'm asking for, but I'd like to know if there is a faster way. Assuming listToCull is a list of PVectors with duplicates:
Set<PVector> pointSet = new LinkedHashSet<PVector>(listToCull);
List<PVector> uniqueItemsInListToCull = new ArrayList<PVector>();
for(PVector pt : pointSet){
int counter=0;
for(PVector ptCheck : listToCull){
if(pt==ptCheck){
counter++;
}
}
if(counter<2){
uniqueItemsInListToCull.add(pt);
}
}
uniqueItemsInListToCull will be different from pointSet. I'd like to do this without loops if possible.
You will have to do some programming yourself: Create two empty sets; on will contain the unique elements, the other the duplicates. Then loop through the elements of listToCull. For each element, check whether it is in the duplicate set. If it is, ignore it. Otherwise, check if it is in the unique element set. If it is, remove it there and add to the duplicates set. Otherwise, add it to the unique elements set.
If your PVector class has a good hashCode() method, HashSets are quite efficient, so the performance of this will not be too bad.
Untested:
Set<PVector> uniques = new HashSet<>();
Set<PVector> duplicates = new HashSet<>();
for (PVector p : listToCull) {
if (!duplicates.contains(p)) {
if (uniques.contains(p)) {
uniques.remove(p);
duplicates.add(p);
}
else {
uniques.add(p);
}
}
}
Alternatively, you may use a third-party library which offers a Bag or MultiSet. This allows you to count how many occurrences of each element are in the collection, and then at the end discard all elements where the count is different than 1.
What you are looking for is the intersection:
Assuming that PVector (terrible name by the way) implements hashCode() and equals() correctly a Set will eliminate duplicates.
If you want a intersection of the List and an existing Set create a Set from the List then use Sets.intersection() from Guava to get the ones common to both sets.
public static <E> Sets.SetView<E> intersection(Set<E> set1, Set<?> set2)
Returns an unmodifiable view of the intersection of two sets. The returned set contains all
elements that are contained by both backing sets. The iteration order
of the returned set matches that of set1. Results are undefined if
set1 and set2 are sets based on different equivalence relations (as
HashSet, TreeSet, and the keySet of an IdentityHashMap all are).
Note: The returned view performs slightly better when set1 is the
smaller of the two sets. If you have reason to believe one of your
sets will generally be smaller than the other, pass it first.
Unfortunately, since this method sets the generic type of the returned
set based on the type of the first set passed, this could in rare
cases force you to make a cast, for example:
Set aFewBadObjects = ... Set manyBadStrings =
...
// impossible for a non-String to be in the intersection
SuppressWarnings("unchecked") Set badStrings = (Set)
Sets.intersection(
aFewBadObjects, manyBadStrings); This is unfortunate, but should come up only very rarely.
You can also do union, complement, difference and cartesianProduct as well as filtering very easily.
So you want pointSet to hold the items in listToCull which have no duplicates? Is that right?
I would be inclined to create a Map, then iterate twice over the list, the first time putting a value of zero in for each PVector, the second time adding one to the value for each PVector, so at the end you have a map with counts. Now you're interested in the keys of the map for which the value is exactly equal to one.
It's not perfectly efficient - you're operating on list items more times than absolutely necessary - but it's quite clean and simple.
OK, here's the solution I've come up with, I'm sure there are better ones out there but this one's working for me. Thanks to all who gave direction!
To get unique items, you can run a Set, where listToCull is a list of PVectors with duplicates:
List<PVector> culledList = new ArrayList<PVector>();
Set<PVector> pointSet = new LinkedHashSet<PVector>(listToCull);
culledList.addAll(pointSet);
To go further, suppose you want a list where you've removed all items in listToCull which have a duplicate. You can iterate through the list and test whether it's in the set for each item. This let's us do one loop, rather than a nested loop:
Set<PVector> pointSet = new HashSet<PVector>(listToCull);
Set<PVector> removalList = new HashSet<PVector>();//list to remove
for (PVector pt : listToCull) {
if (pointSet.contains(pt)) {
removalList.add(pt);
}
else{
pointSet.add(pt);
}
}
pointSet.removeAll(removalList);
List<PVector> onlyUniquePts = new ArrayList<PVector>();
onlyUniquePts.addAll(pointSet);

Is there a list implementation that would allow gaps?

I'm looking for a collection that would be some sort of a list that allows gaps. The objectives are:
every element has some index in the collection that is meaningful.
the collection is to be sparse and not continuous; its size should return the number of proper elements, hence the workaround of initializing with null wouldn't work.
subList method is desirable to access sublists according to index intervals
Sample use case:
List<Integer> list = /* ? */;
list.add(0,5);
list.add(1,4);
list.add(5,3);
for( Integer i : list )
{
System.out.print( i + " " );
}
/* desired output : "5 4 3 "*/
Use a Map<Integer,Integer>. The key would be your index and the value the value of the list.
For your subList requirement, perhaps TreeMap<Integer,Integer> would work, as it keeps the keys sorted and makes it easy to iterate over a sub-list.
Of course this means you can't use the List interface. If you must use the List interface, you can make your own List implementation backed by a TreeMap (for example, list.add(5,3) would call map.put(5,3)).
You may use a Map and only set the keys you need.
You can keep the insertion order if you want, take a look: Java Class that implements Map and keeps insertion order

How To Prevent Duplicates In Object ArrayList

I have a custom object array list, the object must be in an array list however i have some duplicates in the list and i want to preform a check before i do an add to the list. How can this be achieved. The victimSocialSecurityNumber is unique. Under is my code:
CODE
while (rs.next()){
Citizens victims = new Citizens();
victims.setSocialSecurityNumber(rs.getInt("victimSocialSecurityNumber"));
victims.setfName(rs.getString("victimFName"));
victims.setlName(rs.getString("victimLName"));
victims.setPhoto(rs.getString("victimPhoto"));
victims.setName(rs.getString("victimFName") +" "+ rs.getString("victimLName"));
crime.getVictims().add(victims);
you can convert arraylist to set and back to get rid of the duplicates or use directly structure which allows only sorted unique elements : LinkedHashSet
Assuming Citizens overrides equals, you can do it like this
if (!crime.getVictims().contains(victims)) {
crime.getVictims().add(victims);
}
though generally when duplicates are not allowed the solution is Set
If you have doubts how to override equals / hashCode read http://javarevisited.blogspot.com/2011/10/override-hashcode-in-java-example.html
You can use a hash set to add the objects and convert it to an Arraylist. This can help you to check whether the victim is unique.
CODE
Set hashset = new HashSet();
while (rs.next()){
Citizens victims = new Citizens();
victims.setSocialSecurityNumber(rs.getInt("victimSocialSecurityNumber"));
victims.setfName(rs.getString("victimFName"));
victims.setlName(rs.getString("victimLName"));
victims.setPhoto(rs.getString("victimPhoto"));
victims.setName(rs.getString("victimFName") +" "+ rs.getString("victimLName"));
hashset.add(victims);
}
List list = new ArrayList(hashset);
I could be completely wrong here, but wouldn't a for loop solve your problem? You could just compare what you are about to add to all the elements in the arraylist, and if there are no matches add it, and if there is don't?

Efficient way to get elements out of a treeset with different sorting criteria

I have a treeset containing student objects(name, roll number, address and age) and are stored in ascending order of their names and if the names are same, then roll numbers. This list is coming from a file and could get really big.
Now i have to provide a way to display the list that could be in any order - sorted in ascending/descending order according to name, age, address or roll number. I am looking for an efficient solution for my problem.
What i am thinking of doing is to take a temporary arraylist and get the elements into it in the order i want. But for this i will have to implement a different method for every criteria and this looks inefficient to me.
Is there any way i can get the elements in the treeset out in the way i want into an array coz i just need to print the values and destroy the temp list afterwards
The only way to do it is, as you said, iterating over the tree and pulling out all of the matching elements into an ArrayList. Once you've done that you can sort based on a particular Comparator.
If you just want to pull out elements based on the natural ordering, you can use the subset method, but that depends on the compareTo method in the tree, which is not valid for all the different searches that you want to do.
Given that, why are you using a TreeSet in the first place? Do your elements have a natural ordering that the TreeSet leverages? If not why not just dump them all into an ArrayList and sort the ArrayList as necessary?

Categories