remove duplicate strings in a List in Java - java

Update:
I guess HashSet.add(Object obj) does not call contains. is there a way to implement what I want(remove dup strings ignore case using Set)?
Original question:
trying to remove dups from a list of String in java, however in the following code CaseInsensitiveSet.contains(Object ob) is not getting called, why?
public static List<String> removeDupList(List<String>list, boolean ignoreCase){
Set<String> set = (ignoreCase?new CaseInsensitiveSet():new LinkedHashSet<String>());
set.addAll(list);
List<String> res = new Vector<String>(set);
return res;
}
public class CaseInsensitiveSet extends LinkedHashSet<String>{
#Override
public boolean contains(Object obj){
//this not getting called.
if(obj instanceof String){
return super.contains(((String)obj).toLowerCase());
}
return super.contains(obj);
}
}

Try
Set set = new TreeSet(String.CASE_INSENSITIVE_ORDER);
set.addAll(list);
return new ArrayList(set);
UPDATE but as Tom Anderson mentioned it does not preserve the initial order, if this is really an issue try
Set<String> set = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
Iterator<String> i = list.iterator();
while (i.hasNext()) {
String s = i.next();
if (set.contains(s)) {
i.remove();
}
else {
set.add(s);
}
}
prints
[2, 1]

contains is not called as LinkedHashSet is not implemented that way.
If you want add() to call contains() you will need to override it as well.
The reason it is not implemented this way is that calling contains first would mean you are performing two lookups instead of one which would be slower.

add() method of LinkedHashSet do not call contains() internally else your method would have been called as well.
Instead of a LinkedHashSet, why dont you use a SortedSet with a case insensitive comparator
? With the String.CASE_INSENSITIVE_ORDER comparator
Your code is reduced to
public static List<String> removeDupList(List<String>list, boolean ignoreCase){
Set<String> set = (ignoreCase?new TreeSet<String>(String.CASE_INSENSITIVE_ORDER):new LinkedHashSet<String>());
set.addAll(list);
List<String> res = new ArrayList<String>(set);
return res;
}
If you wish to preserve the Order, as #tom anderson specified in his comment, you can use an auxiliary LinkedHashSet for the order.
You can try adding that element to TreeSet, if it returns true also add it to LinkedHashSet else not.
public static List<String> removeDupList(List<String>list){
Set<String> sortedSet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
List<String> orderedList = new ArrayList<String>();
for(String str : list){
if(sortedSet.add(str)){ // add returns true, if it is not present already else false
orderedList.add(str);
}
}
return orderedList;
}

Try
public boolean addAll(Collection<? extends String> c) {
for(String s : c) {
if(! this.contains(s)) {
this.add(s);
}
}
return super.addAll(c);
}
#Override
public boolean contains(Object o) {
//Do your checking here
// return super.contains(o);
}
This will make sure the contains method is called if you want the code to go through there.

Here's another approach, using a HashSet of the strings for deduplication, but building the result list directly:
public static List<String> removeDupList(List<String> list, boolean ignoreCase) {
HashSet<String> seen = new HashSet<String>();
ArrayList<String> deduplicatedList = new ArrayList<String>();
for (String string : list) {
if (seen.add(ignoreCase ? string.toLowerCase() : string)) {
deduplicatedList.add(string);
}
}
return deduplicatedList;
}
This is fairly simple, makes only one pass over the elements, and does only a lowercase, a hash lookup, and then a list append for each element.

Related

Create Test case for sorted list of strings

I hava a list of strings and in my code I order this list. I want to write a unit test to ensure that the list has been orderer properly. my code
#Test
public void test() {
List<String> orderedList = new ArrayList<String>();
orderedList.add("a");
orderedList.add("b");
orderedList.add("a");
assertThat(orderedList, isInDescendingOrdering());
}
private Matcher<? super List<String>> isInDescendingOrdering()
{
return new TypeSafeMatcher<List<String>>()
{
#Override
public void describeTo (Description description)
{
description.appendText("ignored");
}
#Override
protected boolean matchesSafely (List<String> item)
{
for(int i = 0 ; i < item.size() -1; i++) {
if(item.get(i).equals(item.get(i+1))) return false;
}
return true;
}
};
}
somehow it success al the times.
You are absolutely overcomplicating things here. Writing a custom matcher is a nice exercise, but it does not add any real value to your tests.
Instead I would suggest that you simply create some
String[] expectedArray =....
value and give that to your call to assertThat. That is less sexy, but much easier to read and understand. And that is what counts for unit tests!
You can do it simply by copying the array, then sorting it and finally compare it with original array.
The code is given below:
#Test
public void test() {
List<String> orderedList = new ArrayList<String>();
orderedList.add("a");
orderedList.add("b");
orderedList.add("a");
//Copy the array to sort and then to compare with original
List<String> orderedList2 = new ArrayList<String>(orderedList);
orderedList2.sort((String s1, String s2) -> s1.compareTo(s2));
Assert.assertEquals(orderedList, orderedList2);
}

How to check if TreeMap<String, ArrayList<String>> contains a value? in Java

I'm just wondering how to check if TreeMap> contains a value in Java?
For Example:
/*I have TreeMap<String,ArrayList<String>> map with these elements
* {color = ["red","blue","green"], shape=["square", "circle"]}
*/
System.out.println(map.containsValue("square")); //This return false
System.out.println(map.values().contains("square")); //This return false also
I always get false when I use containsValue() or contains() method. Anybody know why and can give me suggestions, please?
Thanks
Ed
Something like below would work
Map<String,ArrayList<String>> map=new TreeMap<String, ArrayList<String>>();
Collection<ArrayList<String>> values=map.values();
for(ArrayList<String> list:values)
{
list.contains("text_to_search")
{
}
}
You're testing to see whether the map contains a String, "square"-- but the values in your map are ArrayList<String> objects.
If you know that you're looking for a shape, you can first get the "shape" list, and test to see whether it contains the specific shape "square".
ArrayList<String> shapes = map.get("shape");
boolean containsSquare = shapes.contains("square");
public boolean valueExists(String value){
for(Map.Entry<String,ArrayList<String>> entry : treeMap.entrySet()) {
String key = entry.getKey();
ArrayList<String> values = entry.getValue();
for (String str:values){
if (value.equals(str)){
return true;
}
}
}
return false;
}

how to get duplicated and non duplicated element of arrayList?

I have an object as Riziv with three variables as id, cnk and product. Then I search in a databank for this object and add it to a ArrayList as ArrayList<Riziv> list.
Now I should checkout if all object in his array are the same cnk then return true otherwise I should return all objects which are not the same cnk with error message.
public class Riziv{ String id, cnk, product; }
ArrayList<Riziv> list = getArrayListFromDatabank(id);
public void getDuplicatedWhichHasTheSameCnk(){
}
}
Using standard JVM structures (MultiMap is provided by guava), you can do that:
public List<Riviz> getDuplicates(final List<Riviz> l)
{
final HashMap<String, List<Riviz>> m = new HashMap<String, List<Riviz>>();
final List<Riviz> ret = new ArrayList<Riviz>();
String cnk;
for (final Riviz r: l) {
cnk = r.getCnk();
if (!m.contains(cnk))
m.add(cnk, new ArrayList<Riviz>());
m.get(cnk).add(r);
}
List<Riviz> tmp;
for (final Map.Entry<String, List<Riviz>> entry: m.entrySet()) {
tmp = entry.getValue();
if (tmp.size() == 1) // no dups
continue;
ret.addAll(tmp);
}
return ret;
}
ret will contain the duplicates. You can change that function to return a Map<String, Riviz> instead, and filter out entries where the list size is only one. You'll then get a map with the conflicting cnks as keys and a list of dups as values.
I am not clear exactly what you want however I suspect you want something like this.
MultiMap<Key, Riziv> multiMap =
List<Riziv> list =
for(Riziv r: list)
multiMap.put(r.getCnk(), r);
for(Key cnk: multiMap.keySet()) {
Collection<Riziv> sameCnk = multiMap.get(cnk);
// check size and compare entries
}
The multi-map will have the list of Riziv objects for each Cnk.
One way to do it is write a comparator to sort the list by cnk String and then compare each consecutive cnk String to the next, if you find a duplicate, they will be right next to eachother.
1.) Sort the list using a comparator by sorting on the cnk variable.
2.) Compare each element in the list to the next for duplicates.
There's probably many other ways to solve this, this is just the first that came to mind.
I did not test this so you have been forewarned lol:
ArrayList<Riziv> rizArray = new ArrayList<Riziv>();
//Sort the array by the CNK variable.
Collections.sort(rizArray, new Comparator<Riziv>(){
#Override
public int compare(Riziv arg0, Riziv arg1) {
//Return the comparison of the Strings.
//Use .compareToIgnoreCase if you want to ignore upper/lower case.
return arg0.getCnk().compareTo(arg1.getCnk());
}
});
//List should be in alphabetical order at this point.
List<Riziv> duplicates = new ArrayList<Riziv>();
Riziv rizPrevious = null;
for(Riziv riz: rizArray){
if(rizPrevious == null){
rizPrevious = riz;
continue;
}
if(riz.getCnk().compareTo(rizPrevious.getCnk()) == 0){
duplicates.add(riz);
}
rizPrevious = riz;
}

How to remove specific object from ArrayList in Java?

How can I remove specific object from ArrayList?
Suppose I have a class as below:
import java.util.ArrayList;
public class ArrayTest {
int i;
public static void main(String args[]){
ArrayList<ArrayTest> test=new ArrayList<ArrayTest>();
ArrayTest obj;
obj=new ArrayTest(1);
test.add(obj);
obj=new ArrayTest(2);
test.add(obj);
obj=new ArrayTest(3);
test.add(obj);
}
public ArrayTest(int i){
this.i=i;
}
}
How can I remove object with new ArrayTest(1) from my ArrayList<ArrayList>
ArrayList removes objects based on the equals(Object obj) method. So you should implement properly this method. Something like:
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj == this) return true;
if (!(obj instanceof ArrayTest)) return false;
ArrayTest o = (ArrayTest) obj;
return o.i == this.i;
}
Or
public boolean equals(Object obj) {
if (obj instanceof ArrayTest) {
ArrayTest o = (ArrayTest) obj;
return o.i == this.i;
}
return false;
}
If you are using Java 8 or above:
test.removeIf(t -> t.i == 1);
Java 8 has a removeIf method in the collection interface. For the ArrayList, it has an advanced implementation (order of n).
In general an object can be removed in two ways from an ArrayList (or generally any List), by index (remove(int)) and by object (remove(Object)).
In this particular scenario: Add an equals(Object) method to your ArrayTest class. That will allow ArrayList.remove(Object) to identify the correct object.
For removing the particular object from arrayList there are two ways. Call the function of arrayList.
Removing on the basis of the object.
arrayList.remove(object);
This will remove your object but in most cases when arrayList contains the items of UserDefined DataTypes, this method does not give you the correct result. It works fine only for Primitive DataTypes. Because user want to remove the item on the basis of object field value and that can not be compared by remove function automatically.
Removing on the basis of specified index position of arrayList. The best way to remove any item or object from arrayList. First, find the index of the item which you want to remove. Then call this arrayList method, this method removes the item on index basis. And it will give the correct result.
arrayList.remove(index);
Here is full example. we have to use
Iterator's remove() method
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayTest {
int i;
public static void main(String args[]) {
ArrayList<ArrayTest> test = new ArrayList<ArrayTest>();
ArrayTest obj;
obj = new ArrayTest(1);
test.add(obj);
obj = new ArrayTest(2);
test.add(obj);
obj = new ArrayTest(3);
test.add(obj);
System.out.println("Before removing size is " + test.size() + " And Element are : " + test);
Iterator<ArrayTest> itr = test.iterator();
while (itr.hasNext()) {
ArrayTest number = itr.next();
if (number.i == 1) {
itr.remove();
}
}
System.out.println("After removing size is " + test.size() + " And Element are :" + test);
}
public ArrayTest(int i) {
this.i = i;
}
#Override
public String toString() {
return "ArrayTest [i=" + i + "]";
}
}
use this code
test.remove(test.indexOf(obj));
test is your ArrayList and obj is the Object, first you find the index of obj in ArrayList and then you remove it from the ArrayList.
AValchev is right.
A quicker solution would be to parse all elements and compare by an unique property.
String property = "property to delete";
for(int j = 0; j < i.size(); j++)
{
Student obj = i.get(j);
if(obj.getProperty().equals(property)){
//found, delete.
i.remove(j);
break;
}
}
THis is a quick solution. You'd better implement object comparison for larger projects.
If you want to remove multiple objects that are matching to the property try this.
I have used following code to remove element from object array it helped me.
In general an object can be removed in two ways from an ArrayList (or generally any List), by index (remove(int)) and by object (remove(Object)).
some time for you arrayList.remove(index)or arrayList.remove(obj.get(index)) using these lines may not work try to use following code.
for (Iterator<DetailInbox> iter = detailInboxArray.iterator(); iter.hasNext(); ) {
DetailInbox element = iter.next();
if (element.isSelected()) {
iter.remove();
}
}
I have tried this and it works for me:
ArrayList<cartItem> cartItems= new ArrayList<>();
//filling the cartItems
cartItem ci=new cartItem(itemcode,itemQuantity);//the one I want to remove
Iterator<cartItem> itr =cartItems.iterator();
while (itr.hasNext()){
cartItem ci_itr=itr.next();
if (ci_itr.getClass() == ci.getClass()){
itr.remove();
return;
}
}
ArrayTest obj=new ArrayTest(1);
test.add(obj);
ArrayTest obj1=new ArrayTest(2);
test.add(obj1);
ArrayTest obj2=new ArrayTest(3);
test.add(obj2);
test.remove(object of ArrayTest);
you can specify how you control each object.
You can use Collections.binarySearch to find the element, then call remove on the returned index.
See the documentation for Collections.binarySearch here:
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html#binarySearch%28java.util.List,%20java.lang.Object%29
This would require the ArrayTest object to have .equals implemented though. You would also need to call Collections.sort to sort the list. Finally, ArrayTest would have to implement the Comparable interface, so that binarySearch would run correctly.
This is the "proper" way to do it in Java. If you are just looking to solve the problem in a quick and dirty fashion, then you can just iterate over the elements and remove the one with the attribute you are looking for.
This helped me:
card temperaryCardFour = theDeck.get(theDeck.size() - 1);
theDeck.remove(temperaryCardFour);
instead of
theDeck.remove(numberNeededRemoved);
I got a removal conformation on the first snippet of code and an un removal conformation on the second.
Try switching your code with the first snippet I think that is your problem.
Nathan Nelson
simple use remove() function. and pass object as param u want to remove.
ur arraylist.remove(obj)
or you can use java 8 lambda
test.removeIf(i -> i==2);
it will simply remove all object that meet the condition
Below one is used when removed ArrayTest(1) from test ArrayList
test.removeIf(
(intValue) -> {
boolean remove = false;
remove = (intValue == 1);
if (remove) {
//Success
}
return remove;
});
Example within a simple String List, if anyone wants :
public ArrayList<String> listAfterRemoved(ArrayList<String> arrayList, String toRemove) {
for (int i = 0; i < arrayList.size(); i++) {
if (arrayList.get(i).equals(toRemove)) {
arrayList.remove(toRemove);
}
}
return arrayList;
}
And the call is :
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("1");
arrayList.add("2");
arrayList.add("3");
arrayList.add("4");
System.out.println("Array List before: " + arrayList.toString());
arrayList = listAfterRemoved(arrayList, "2");
System.out.println("Array List after : " + arrayList.toString());
If you want to remove or filter specific object from ArrayList, there are many ways that you can use it as given below:
Suppose list is the reference variable of arrayList.
List<Student> list = ...;// Stored the objects here
If you know the specific Student object that you want to delete then you can use it simply:
list.remove(student) //if you know the student object
If you know the specific id or name of that student, in that case, use java 8 Collection.removeIf():
list.removeIf(fandom -> id == fandom.getId());
Another way that you can use that is Collectors.partitioningBy:
Map<Boolean, List<Student>> studentsElements = list
.stream()
.collect(Collectors.partitioningBy((Student st) ->
!name.equals(st.getName())));
// All Students who do have not that specific name
List<Student> matching = studentsElements.get(true));
// All Student who has only that specific name
List<Student> nonMatching = studentsElements.get(false));
Or you can simply filter that specific Object
List<Student> studentsElements = list
.stream()
.filter(e -> !name.equals(st.getName()))
.collect(Collectors.toList());

How to get index of an item in java.util.Set

I know the differences between Set and List(unique vs. duplications allowed, not ordered/ordered, etc). What I'm looking for is a set that keeps the elements ordered(that's easy), but I also need to be able to recover the index in which an element was inserted. So if I insert four elements, then I want to be able to know the order in which one of them was inserted.
MySet<String> set = MySet<String>();
set.add("one");
set.add("two");
set.add("three");
set.add("four");
int index = set.getIndex("two");
So at any given moment I can check if a String was already added, and get the index of the string in the set. Is there anything like this, or I need to implement it myself?
After creating Set just convert it to List and get by index from List:
Set<String> stringsSet = new HashSet<>();
stringsSet.add("string1");
stringsSet.add("string2");
List<String> stringsList = new ArrayList<>(stringsSet);
stringsList.get(0); // "string1";
stringsList.get(1); // "string2";
A small static custom method in a Util class would help:
public static <T> int getIndex(Set<T> set, T value) {
int result = 0;
for (T entry:set) {
if (entry.equals(value)) return result;
result++;
}
return -1;
}
If you need/want one class that is a Set and offers a getIndex() method, I strongly suggest to implement a new Set and use the decorator pattern:
public class IndexAwareSet<T> implements Set {
private Set<T> set;
public IndexAwareSet(Set<T> set) {
this.set = set;
}
// ... implement all methods from Set and delegate to the internal Set
public int getIndex(T entry) {
int result = 0;
for (T entry:set) {
if (entry.equals(value)) return result;
result++;
}
return -1;
}
}
you can extend LinkedHashSet adding your desired getIndex() method. It's 15 minutes to implement and test it. Just go through the set using iterator and counter, check the object for equality. If found, return the counter.
One solution (though not very pretty) is to use Apache common List/Set mutation
import org.apache.commons.collections.list.SetUniqueList;
final List<Long> vertexes=SetUniqueList.setUniqueList(new LinkedList<>());
it is a list without duplicates
https://commons.apache.org/proper/commons-collections/javadocs/api-3.2.2/index.html?org/apache/commons/collections/list/SetUniqueList.html
How about add the strings to a hashtable where the value is an index:
Hashtable<String, Integer> itemIndex = new Hashtable<>();
itemIndex.put("First String",1);
itemIndex.put("Second String",2);
itemIndex.put("Third String",3);
int indexOfThirdString = itemIndex.get("Third String");
you can send your set data to a new list
Java ArrayList<String> myList = new ArrayList<>(); myList.addAll(uniqueNameSet); myList.indexOf("xxx");

Categories

Resources