How To Prevent Duplicates In Object ArrayList - java

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?

Related

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

Trouble putting only unique values into an array

So I have a list of countries that I am reading from a text file and some of the countries are on there more than once. I need to put each country name into a string array without any doubles, or countries put on there twice. I tried using a for loop but could not wrap my head around the logic required for this.
Thanks in advance.
Try using a Set. A Set can contain one and not more than one of a particular instance (instance1.equals(instance2) will not be true).
Instantiate a Set like so:
Set<String> s = new HashSet<String>();
Then use a for loop to add the values.
String[] countries = {"JP", "US", "CN", "RU", "RU"}; //just make pretend these were read from a file.
for (String countryName: countries){
s.add(countryName); // RU will only be added once
}
System.out.println(s);
Outputs: [JP, US, RU, CN]
There are three different ways I can see this working:
Use a Set. This is the most efficient and easiest, and uses code that works
Each time you read in an element, iterate through the array, and see if the array already contains the element. If it does, don't add it. If you can't use Sets, this is the easiest code to write.
Read in all of the elements, sort the array. Iterate through the array, and if the current element doesn't equal the previous element, then add it to a new array. This is more efficient than #2 (O(nlog(n)) vs O(n^2)), but will require more code.
In order to check to see if a country is in the array, use an if statement. As you read in each country this checks to see if if exists in the array. If it doesn't, it adds the country to the array.
if(!Arrays.asList(yourArr).contains(country)){
yourArr[i] = country;
}

Reliability of `TreeSet` for orderability

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.

Looping issue in for loop while avoiding duplicate entries

In selected contact i am having duplicate values so that iam first taking copy of selected contact copy
for(int q=0;q<selectedcontact.size();q++)
{
selectedcontactcopy.add(selectedcontact.get(q));
}
and then Comparing two array list
for(int r=0;r<selectedcontactcopy.size();r++)
{
for(int j=0;j<selectedcontact.size();j++)
{
if(r!=j && r<j)
{
if(selectedcontactcopy.get(r).getLandLineNumber().toString().trim().equals(selectedcontact.get(j).getLandLineNumber().toString().trim()))
{
Log.i("hai",selectedcontact.get(j).getLandLineNumber().toString());
selectedcontact.remove(j);
j--;
}
}
}
}
But the situation is that first duplication is avoided then the arraylist won't compare the next consecutive values
This is a bad way of doing a uniqueness check. A better method is to make use of the functionality of java.util.Set - make sure your contacts implement Comparable and compare landline numbers, and then add them to the set and iterate over the set contents.
Set guarantees you uniqueness, and provides a far cleaner interface than nested for loops.
Use HashSet to avoid repeated values from ArrayList,
Something like,
ArrayList arrayList = new ArrayList(); // Your ArrayList which contains repeated values
HashSet hashSet = new HashSet();
hashSet.addAll(arrayList);
arrayList.clear();
arrayList.addAll(hashSet);
The easiest way to remove repeated elements is to add the contents to a Set (which will not allow duplicates) and then add the Set back to the ArrayList.
there is no need to create 2 lists for this.
create a HashMap with keys as the landline number and value as the whole contact object.
iterate over the list 'selectedContacts' and put all the elements into the hashmap.
finally, iterate over the hashmap created and store all the values in the hashmap into a list of contacts.
hope it helps.

Categories