Comparing Two ArrayLists to Get Unique and Duplicate Values - java

I have two ArrayLists as shown - pinklist and normallist. I am comparing both of them and finding the unique and duplicate values from both as shown below in code:
List<String> pinklist = t2.getList();
List<String> normallist = t.getList();
ArrayList<String> duplicatevalues = new ArrayList<String>();
ArrayList<String> uniquevalues = new ArrayList<String>();
for (String finalval : pinklist) {
if (pinklist.contains(normallist)) {
duplicatevalues.add(finalval);
} else if (!normallist.contains(pinklist)) {
uniquevalues.add(finalval);
}
}
I am getting the duplicateValues properly, but I am not getting the unique values.

this should do:
List<String> pinklist = t2.getList();
List<String> normallist = t.getList();
ArrayList<String> duplicates = new ArrayList<String>(normallist);
duplicates.retainAll(pinklist);
ArrayList<String> uniques = new ArrayList<String>(normallist);
uniques.removeAll(pinklist);
Explaination:
Every List can take another list as a constructor parameter, and copy it's values.
retainAll(list2) will remove all entries, that does not exist in list2.
removeAll(list2) will remove all entries, that does exist in list2.
We don't want to remove/retain on the original lists, because this will modify it, so we copy them, in the constructor.

You're ignoring finalval in your conditions, instead asking whether one list contains the other list.
You could do it like this:
// Variable names edited for readability
for (String item : pinkList) {
if (normalList.contains(item)) {
duplicateList.add(item);
} else {
uniqueList.add(item);
}
}
I wouldn't really call these "unique" or "duplicate" items though - those are usually about items within one collection. This is just testing whether each item from one list is in another. It's more like "existing" and "new" in this case, I'd say.
Note that as you're treating these in a set-based way, I'd suggest using a set implementation such as HashSet<E> instead of lists. The Sets class in Guava provides useful methods for working with sets.

Try ListUtils https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/ListUtils.html
To get duplicate values use ListUtils.intersection(list1, list2)
To get unique values you could use ListUtils.sum(list1, list2) and then subtract the duplicates list

Do it this way -
for (String finalval : pinklist)
{
if(normallist.contains(finalval))
{
// finalval is both in pinklist and in
// normallist. Add it as a duplicate.
duplicatevalues.add(finalval); // this will get you the duplicate values
}
else {
// finalval is in pinklist but not in
// normallist. Add it as unique.
uniquevalues.add(finalval); // this will get you the values which are in
// pinklist but not in normallist
}
}
// This will give you the values which are
// in normallist but not in pinklist.
for(String value : normallist) {
if(!pinklist.contains(value)) {
uniquevalues.add(value);
}
}

Using Java8 Stream API we can filter lists and get expected results.
List<String> listOne = // Your list1
List<String> listTwo = // Your list2
List<String> uniqueElementsFromBothList = new ArrayList<>();
List<String> commonElementsFromBothList = new ArrayList<>();
// Duplicate/Common elements from both lists
commonElementsFromBothList.addAll(
listOne.stream()
.filter(str -> listTwo.contains(str))
.collect(Collectors.toList()));
// Unique element from listOne
uniqueElementsFromBothList.addAll(
listOne.stream()
.filter(str -> !listTwo.contains(str))
.collect(Collectors.toList()));
// Unique element from listOne and listTwo
// Here adding unique elements of listTwo in existing unique elements list (i.e. unique from listOne)
uniqueElementsFromBothList.addAll(
listTwo.stream()
.filter(str -> !listOne.contains(str))
.collect(Collectors.toList()));

Here's my solution to the problem.
We can create a set containing elements from both the lists.
For the unique elements, using the Stream API, we can filter out the elements based on the predicates returning XOR of contains method. it will return true only for true ^ false OR false ^ true, ensuring only one of them contains it.
For the distinct elements, simply change the XOR to &&, and it'll check if both lists have the objects or not.
Code:
private static void uniqueAndDuplicateElements(List<String> a, List<String> b) {
Set<String> containsAll = new HashSet<String>();
containsAll.addAll(a);
containsAll.addAll(b);
List<String> uniquevalues = containsAll.stream()
.filter(str -> a.contains(str) ^ b.contains(str))
.collect(Collectors.toList());
List<String> duplicatevalues = containsAll.stream()
.filter(str -> a.contains(str) && b.contains(str))
.collect(Collectors.toList());
System.out.println("Unique elements from both lists: " + uniquevalues);
System.out.println("Elements present in both lists: " + duplicatevalues);
}

Why are you passing entire list to the contains method? You should pass finalval rather.

Related

How could i transfer duplicate items in other ArrayList?

I have an array list
ArrayList<String> list=new ArrayList<String>();
list.add("Apple");
list.add("Ball");
list.add("Ball");
list.add("Cat");
list.add("Cat");
list.add("dog");
and I want to transfer duplicate strings to other ArrayList.
I mean 2nd array list should only contain Ball and Cat not Apple and dog.
Any kind of help is appreciated.
You can do this:
List<String> duplicates = new ArrayList<String>();
for(String str: list) {
if(Collections.frequency(list, str) > 1) {
duplicates.add(str);
}
}
duplicates will contain your duplicates
Try this:
// Custom list to ensure that one duplicate gets added to a list at most as
// opposed to n-1 instances (only two instances of a value in this list would
// be deceiving).
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Ball");
list.add("Ball");
list.add("Ball");
list.add("Ball");
list.add("Cat");
list.add("Cat");
list.add("Cat");
list.add("dog");
list.add("dog");
Set<String> set = new HashSet<>();
Set<String> setOfDuplicates = new HashSet<>();
for (String s : list) {
if (!set.add(s)) { // Remember that sets do not accept duplicates
setOfDuplicates.add(s);
}
}
List<String> listOfDuplicates = new ArrayList<>(setOfDuplicates);
You can use a Set as a way to help determine the duplicated elements then simply return an ArrayList of those elements.
public static ArrayList<String> retainDuplicates(ArrayList<String> inputList){
Set<String> tempSet = new HashSet<>();
ArrayList<String> duplicateList = new ArrayList<>();
for (String elem : inputList) {
if(!tempSet.add(elem)) duplicateList.add(elem);
}
return duplicateList.stream().distinct().collect(Collectors.toCollection(ArrayList::new));
}
call the method like so:
ArrayList<String> resultList = retainDuplicates(list);
note that I've used distinct() to remove any elements that occur more than once within the duplicateList. However, if you want to keep the duplicates regardless of theirs occurrences within the duplicateList then just perform return duplicateList; rather than return duplicateList.stream().distinct().collect(Collectors.toCollection(ArrayList::new));.
since you said your duplicates will all be next to each other, you can itterate through the list in pairs, and if the pair's elements match, there is a duplicate
here would be the general pseudo code for it
int first = 0
int second = 1
for (arraySize)
if (array[first] == array[second])
//there is a match here
newArray.add(array[first])
first += 1
second += 1
Note that this does not check the bounds of the array, which should be easy to implement yourself
now as for the second list not having duplicate items, you can simply store a variable with the last transfered item, and if the new found duplicate is the same, dont transfer it again
ArrayList<String> list=new ArrayList<String>();
list.add("Apple");
list.add("Ball");
list.add("Ball");
list.add("Cat");
list.add("Cat");
list.add("dog");
List<String> duplicateList= new ArrayList<String>();
for(String str: list) {
if(Collections.frequency(list, str) > 1) {
duplicateList.add(str);
}
}
System.out.println(duplicateList.toString());
//Here you will get duplicate String from the original list.

Comparing an arrayList with a Set in java

My set looks like this,
final public static Set<String> env = new HashSet<String>(
Arrays.asList("DEV", "QA", "PREPROD", "PROD"));
And my arrayList will be populated dynamically from DB which will have all the 4 or lesser than that (ex: DEV,QA)
How do i find the missing elements in arraylist and print those?
Given two collections, a and b, here is a way to list the contents of a that are not also in b.
a.stream()
.filter(x -> !b.contains(x))
.forEach(System.out::println);
Without streams, you could do this:
for (String x : a) {
if (!b.contains(x)) {
System.out.println(x);
}
}
Copy the Set and remove all of the elements in the List using the removeAll method. You'll be left with a Set containing the missing ones:
List<String> list = ...;
Set<String> set = ...;
Set<String> copy = new HashSet<>(set);
copy.removeAll(list);
System.out.println(copy);
You should use an Enum that contains all possible values in code.
Then you could do :
Arrays.asList(YourEnum.values()).removeAll(<elements_got_from_database>));
for (String element : array)
if (!otherarray.contains(element))
print(element);

Java. How to delete duplicate objects from both Lists

2nd question, which is continue of first.
I have got two Lists of strings. There is an List of strings (asu) - M1, M2, M3 ... As well as an List of string (rzs) - M1, M2, M3 and all possible combinations thereof. The need for each element (asu) (for example M1) to find an element in (rzs) (M1, M1M2, ..), which contains (e.g. M1). Example: took M1 from (asu) and will start search for duplicate(contain) in (rzs). We found M1M2 in (rzs), it contains M1. After that we should delete both elements from lists. Great thanks to No Idea For Name helped for modification this code. But the program always fails because AbstractList.remove error. Please help to implementation logic and tuning code!
Imports..........
public class work{
List<string> asu = Arrays.asList("M1","M1","M1","M3","M4","M5","M1","M1","M1","M4","M5","M5");
List<string> rzs = Arrays.asList("M1","M2","M3","M4","M5",
"M1M2","M1M3","M1M4","M1M5","M2M3","M2M4","M2M5","M3M4","M3M5","M4M5"
,"M1M2M3","M1M2M4","M1M2M5","M1M3M4","M1M3M4","M1M4M5","M2M4","M2M5");
public static void main(String[] args) {
work bebebe = new work();
bebebe.mywork();
}
List<string> tmp1 = new ArrayList<string>();
List<string> tmp2 = new ArrayList<string>();
System.out.println(Arrays.deepToString(rzs));
System.out.println(Arrays.deepToString(asu));
for (string curr : asu){
for (string currRzs : rzs){
System.out.println("New iteration ");
if (currRzs.contains(curr)) {
System.out.println("Element ("+curr+") in ASU =
element ("+currRzs+") in RZS");
if(tmp1.contains(curr) == false)
tmp1.add(curr);
if(tmp2.contains(currRzs) == false)
tmp2.add(currRzs);
}
}
}
for (string curr : tmp1){
asu.remove(curr);
}
for (string currRzs : tmp2){
rzs.remove(currRzs);
}
You should try to make use of removeAll() or retainAll() methods of Collection.
For example:
List<String> aList = new ArrayList<String>();
aList.add("a");
aList.add("b");
aList.add("c");
aList.add("d");
aList.add("e");
List<String> bList = new ArrayList<String>();
bList.add("b");
bList.add("e");
bList.add("d");
aList.removeAll(bList);
will give you the "a" and "c" elements left in aList
While if you try to make use of retainAll() method:
aList.retainAll(bList);
will give you "b", "d" and "e" elements left in aList;
retainAll() is used to remove all the elements of the invoking collection which are not part of the given collection.
removeAll() is used to remove all the elements of a collection from another collection.
So, it all depends on your use-case.
EDIT
If in any case you want to remove some elements from these collections while iterating conditionally then you should first obtain the Iterator<Type> then call the remove() method over it.
Like:
while(iterator.hasNext()){
String str = iterator.next();
if(str.equals('test')){
iterator.remove();
}
}
Don't remove items from list using foreach loop. Use classic for and iterate over elements, and when removing item, decrease iterator.
To safely remove elements while iterating use Iterator.remove method:
The behavior of an iterator is unspecified if the underlying
collection is modified while the iteration is in progress in any way
other than by calling this method.
Iterator<String> i = tmp1.iterator();
while (i.hasNext()) {
i.next(); // must be called before remove
i.remove();
}
Also it is easier to remove all collection from another by simply calling:
asu.removeAll(tmp1);
instead of List you can use Set, which will remove automatically the duplicate elements...
You can use removeAll() method to remove collection of elements from the list instead of removing one by one.
use
asu.removeAll(tmp1);
instead of
for (string curr : tmp1)
{
asu.remove(curr);
}
and use
rzs.removeAll(tmp2);
instead of
for (string currRzs : tmp2)
{
rzs.remove(currRzs);
}
update
I trace out your problem.The problem lies in Arrays.asList() method.
According to Arrays#asList
asList() returns "a fixed-size list backed by the specified array". If you want to resize the array, you have to create a new one and copy the old data. Then the list won't be backed by the same array instance.
So create a duplicate ArrayList for the lists.Like this
List<string> asuDuplicat = new ArrayList<string>(asu);
List<string> rzsDuplicat = new ArrayList<string>(rzs);
use asuDuplicat,rzsDuplicat.
asuDuplicat.removeAll(tmp1);
rzsDuplicat.removeAll(tmp2);

Java remove duplicates from List store into other list?

I have a list of words which contains multiple duplicate words. I want to extract the words that are duplicated and store them in another list (maintaining the integrity of the original list).
I tried iterating through the list like you see below, but this fails logically because every 'dupe' will at some point be equal to primary. I really want to iterate through the list and for every String in the list check all the OTHER strings in the list for duplicates.
Is there a method in the List interface that allows this type of comparison?
For reference list 1 is a list of Strings.
for(String primary: list1){
for(String dupe: list1){
if(primary.equals(dupe)){
System.out.print(primary + " " + dupe);
ds3.add(primary);
}
}
}
EDIT:
I should note, that I'm aware that a Set doesn't allow for duplicates, but what I'm trying to do is OBTAIN the duplicates. I want to find them, and take them out and use them later. I'm not trying to eradicate them.
The easiest way to remove the duplicates is to add all elements into a Set:
Set<String> nodups = new LinkedHashSet<String>(list1);
List<String> ds3 = new ArrayList<String>(nodups);
In the above code, ds3 will be duplicate-free. Now, if you're interested in finding which elements are duplicate in O(n):
Map<String, Integer> counter = new LinkedHashMap<String, Integer>();
for (String s : list1) {
if (counter.containsKey(s))
counter.put(s, counter.get(s) + 1);
else
counter.put(s, 1);
}
With the above, it's easy to find the duplicated elements:
List<String> ds3 = new ArrayList<String>();
for (Map.Entry<String, Integer> entry : counter.entrySet())
if (entry.getValue() > 1)
ds3.add(entry.getKey());
Yet another way, also O(n): use a Set to keep track of the duplicated elements:
Set<String> seen = new HashSet<String>();
List<String> ds3 = new ArrayList<String>();
for (String s : list1) {
if (seen.contains(s))
ds3.add(s);
else
seen.add(s);
}
Consider using a Set. "A collection that contains no duplicate elements."
The intent is to extract the duplicates not lose them entirely
List<String> list =
Set<String> set = new LinkedHashSet<>(); // to keep he order
List<String> dups = new ArrayList<String>(); // could be duplicate duplicates
for(String s: list)
if (!set.add(s)) dups.add(s);
To obtain only the duplicates (as opposed to eliminating duplicates from the list), you can use a set as a temporary lookup table of what previous string has been visited:
Set<String> tmp = new HashSet<String>();
for(String primary: list1){
if(tmp.contains(primary)) {
// primary is a duplicate
}
tmp.add(primary);
}

Remove duplicates from ArrayLists

I have an ArrayList of custom objects. I want to remove duplicate entries.
The objects have three fields: title, subtitle, and id. If a subtitle occurs multiple times, I only need the first item with thats subtitle (ignore the remaining object with that subtitle).
You can put the content of the ArrayList in a TreeSet using a custom Comparator which should return 0 if the two subtitles are the same.
After that you can convert the Set in a List and have the List without "duplicates".
Here is an example for Object, of course you should use the correct class and logic.
public void removeDuplicates(List<Object> l) {
// ... the list is already populated
Set<Object> s = new TreeSet<Object>(new Comparator<Object>() {
#Override
public int compare(Object o1, Object o2) {
// ... compare the two object according to your requirements
return 0;
}
});
s.addAll(l);
List<Object> res = Arrays.asList(s.toArray());
}
List list = (...);
//list may contain duplicates.
//remove duplicates if any
Set setItems = new LinkedHashSet(list);
list.clear();
list.addAll(setItems);
You may need to override "equals()" so that 2 elements are considered equals if they have the same subtitle (or tite and subtitle maybe ?)
List<Item> result = new ArrayList<Item>();
Set<String> titles = new HashSet<String>();
for(Item item : originalList) {
if(titles.add(item.getTitle()) {
result.add(item);
}
}
add() of the Set returns false if the element already exists.
I would suggest using a Set
http://download.oracle.com/javase/6/docs/api/java/util/Set.html
Which by its nature cannot contain duplicate items. You can create a new set from your original ArrayList using
Set myset = new HashSet(myArrayList);
Alternatively, just use a Set from the start, and don't use an ArrayList as it is not performing the function that you require.
If I understand correctly you have an ArrayList<Custom>, let's call it list. Your Custom class has a subtitle field, let's say with a getSubtitle() method that returns String. You want to keep only the first unique subtitle and remove any remaining duplicates. Here's how you can do that:
Set<String> subtitles = new HashSet<String>();
for (Iterator<Custom> it = list.iterator(); it.hasNext(); ) {
if (!subtitles.add(it.next().getSubtitle())) {
it.remove();
}
}
You can use an O(n^2) solution: Use list.iterator() to iterate the list once, and on each iteration, iterate it again to check if there are duplicates. If there are - call iterator.remove(). A variation of this is to use guava's Iterables.filter(list, predicate) where your filtering logic is in the predicate.
Another way (perhaps better) would be to define the equals(..) and hashCode(..) methods to handle your custom equality logic, and then simply construct a new HashSet(list). This will clear duplicates.
Removes any duplicates in a collection, while preserving the order if it is an ordered collection. Efficient enough for most cases.
public static <I, T extends Collection<I>> T removeDuplicates(T collection)
{
Set<I> setItems = new LinkedHashSet<I>(collection);
collection.clear();
collection.addAll(setItems);
return collection;
}
Update for Java8:
Using Java8 streams you can also do pretty trivally.
ArrayList<String> deduped;
deduped = yourArrayList.stream()
.distinct()
.collect(Collectors.toCollection(ArrayList::new));
This also has the advantage over going ArrayList → Set → ArrayList of maintaining ordering.
Use Collections.sort() to sort and use a simple for cycle to catch doubles, e.g.:
Collections.sort(myList);
A previous = null;
for (A elem: myList) {
if (elem.compareTo(previous) == 0) continue;
previous = elem;
[... process unique element ...]
}
This presumes that you'll implement Comparable in your type A.
private static List<Integer> removeDuplicates(List<Integer> list) {
ArrayList<Integer> uniqueList = new ArrayList<Integer>();
for (Integer i : list) {
if (!inArray(i, uniqueList)) {
uniqueList.add(i);
}
}
return uniqueList;
}
private static boolean inArray(Integer i, List<Integer> list) {
for (Integer integer : list) {
if (integer == i) {
return true;
}
}
return false;
}
The solution depends on circumstances.
If you don't have much data then go with a Set Set<T> unique = new HashSet<>(yourList); (use LinkedHashSet if you care about the order. It creates a new collection, but usually it's not a problem.
When you want to modify existing list and don't want to/can't create a new collection, you can remove duplicates like here:
List<Integer> numbers =
new ArrayList<>(asList(1, 1, 2, 1, 2, 3, 5));
System.out.println("Numbers: " + numbers);
ListIterator<Integer> it = numbers.listIterator();
while (it.hasNext()) {
int i = it.nextIndex();
Integer current = it.next();
for (int j = 0; j < i; ++j) {
if (current.equals(numbers.get(j))) {
it.remove();
break;
}
}
}
System.out.println("Unique: " + numbers);
It works in O(n^2), but it works. Similar implementation, but simpler, is when the list is sorted - works in O(n) time. Both implementations are explained at Farenda: remove duplicates from list - various implementations.
In Java 8, you can also do something like this:
yourList.stream().collect(
Collectors.toMap(
obj -> obj.getSubtitle(),
Function.identity(),
(o1,o2) -> o1))
.values();
The trick is to collect stream to map and provide key collision resolver lambda ((o1,o2) -> o1) which always returns its first parameter.
The result is a Collection, not a List but you can easily convert it to a List:
new ArrayList(resultCollection);
List<YourObject> all = ******** // this is the object that you have already and filled it.
List<YourObject> noRepeat= new ArrayList<YourObject>();
for (YourObject al: all) {
boolean isPresent = false;
// check if the current objects subtitle already exists in noRepeat
for (YourObject nr : noRepeat) {
if (nr.getName().equals(al.getName()) {
isFound = true;//yes we have already
break;
}
}
if (!isPresent)
noRepeat.add(al); // we are adding if we don't have already
}
take one new ArrayList Object of same type
one by one add all the old arraylists elements into this new arraylist object
but before adding every object check in the new arraylist that if there is any object with the same subtitle.if new arraylist contains such subtitle don't add it. otherwise add it
Another method using Java 8 streams you can also do pretty cool:
List<Customer> CustomerLists;
List<Customer> unique = CustomerLists.stream().collect(collectingAndThen(
toCollection(() -> new TreeSet<>(comparingLong(Customer::getId))),
ArrayList::new));

Categories

Resources