Comparing an arrayList with a Set in java - 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);

Related

Remove elements from original list after filtering

For example, in C# I can select elements from original list:
List<string> result = first_mas.Where(d => d == "1").First().ToList();
And if I remove elements from result, same elements also will be removed from first_mas.
In Java I can do something like this:
List<String> result = first_mas.stream().filter(d -> d.equals("1")).collect(Collectors.toList());
But if I remove elements from result they will not be removed from original array.
Is it possible to remove elements from original list after filtering?
UPD:
public void doSomething(List<String> list){
// here remove something from list, should also be removed from original list
// i don't have link to original list here
}
doSomething(first_mas.stream().filter(d -> d.get(0).equals("1")).collect(Collectors.toList()));
You can try this:
List<String> original;
original.removeAll(result);
When you get the result, then you can easily remove all the elements which are in the result List
Probably I do not understand well your question, but why can't you pass the list to doSomething and then manipulate it with Lambdas?
Something like this:
public static void main(String[] args) {
List<String> l = new ArrayList<>();
l.add("a");
l.add("b");
System.out.println(l.size());
doSomething(l);
System.out.println(l.size());
}
private static void doSomething(List<String> l) {
l.stream().filter(s -> s.equals("a")).findFirst().map(l::remove);
}
You should use the Collection.removeIf(predicate) method.
According to the docs:
Removes all of the elements of this collection that satisfy the given predicate.
In your example:
first_mas.removeIf(d -> d.equals("1"));
Or better:
first_mas.removeIf("1"::equals);
In case you do need to do this inside the doSomething(List<String> list) method, just pass the original list as an argument.

Java : Create new ArrayLists based on some condition from existing ArrayList

I am new to java .
I have 2 ArrayLists of Strings
List<String> a= [2,14]
List<String> b= [2,3,4,5]
I want two new ArrayLists
1) List has the value which is in b but not in a
List<String> c= [3,4,5]
2) List has the value a but not in b
List<String> d=[14]
I tried:
List<String> c = new ArrayList<String>(b);
c.removeAll(a);
System.out.println("c::::::::::::::::::::::::::::::"+c); // 2,3,4,5
which is not removing the values of List a
Complete Code
public static void updatePartyType(List<String> oldPartyKeys, List<String> newPartyKeys, String customerCode) {
System.out.println("oldPartyKeys--->"+oldPartyKeys);// 2,14
System.out.println("newPartyKeys--->"+newPartyKeys); // 2,3,4,5
System.out.println("oldPartyKeys class --->"+oldPartyKeys.getClass());// class java.util.ArrayList
List<String> newlySelectedPartyKeys = new ArrayList<String>(newPartyKeys);
newlySelectedPartyKeys.removeAll(oldPartyKeys);
System.out.println("newlySelectedPartyKeys::::::::::::::::::::::::::::"+newlySelectedPartyKeys);
You're really proposing set operations more than list operations - in which case you'd be better off using a HashSet than an ArrayList. Then you could use Collection<E>.removeAll:
Set<String> a = ...;
Set<String> b = ...;
Set<String> c = new HashSet<String>(b);
c.removeAll(a);
Set<String> d = new HashSet<String>(a);
d.removeAll(b);
(This will work for ArrayList as well as HashSet - I've only changed to using sets because it's a more appropriate type when you want set-based operations.)
Or better, use Guava's Sets.difference method:
Set<String> a = ...;
Set<String> b = ...;
Set<String> c = Sets.difference(b, a);
Set<String> d = Sets.difference(a, b);
This will create views on the differences - so changes to the original sets will be reflected in the views. You can effectively take a snapshot of a view by creating a new HashSet:
Set<String> snapshot = new HashSet<String>(c);
This can be done by using the removeAll method:
List<String> c = new ArrayList<>(b);
c.removeAll(a);
List<String> d = new ArrayList<>(a);
d.removeAll(b);
take a look at the addAll() and removeAll() in ArrayList
now you need b\a which is b.removeAll(a)
and a\b which is a.removeAll(b)
A working example (this is for those who are new to Java, so it's verbose):
public static void main(String[] args) {
// first we want to create the lists
// create list a
List<String> a = new ArrayList<String>();
// add members to a
a.add("2");
a.add("14");
// create list b
List<String> b = new ArrayList<String>();
// add members to b
b.add("2");
b.add("3");
b.add("4");
b.add("5");
// create a list in which we store the "filtered" list - duplicated from
// a
List<String> aMinusB = new ArrayList<>(a);
// "filter" using "removeAll" and giving the list b as the argument
aMinusB.removeAll(b);
System.out.println("A minus b:");
// this is short for
// "iterate over the entire list, naming the currently iterated node s"
for (String s : aMinusB) {
System.out.println(s);
}
// duplicate list b in the same manner as above
List<String> bMinusA = new ArrayList<>(b);
// "filter" using "removeAll" and giving the list a as the argument in
// the same manner as above
bMinusA.removeAll(a);
System.out.println("B minus a:");
// this is short for
// "iterate over the entire list, naming the currently iterated node s"
// in the same manner as above
for (String s : bMinusA) {
System.out.println(s);
}
}
Convert your lists to Set instances. Then you can easily find the difference of sets by your own implementation or using a 3rd party library like Google Guava which has Sets.difference(), for example.
addAll elements, then removeAll elements that appears in a.
The time complexity is O(n).

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);

Comparing Two ArrayLists to Get Unique and Duplicate Values

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.

Is there a better way to combine two string sets in java?

I need to combine two string sets while filtering out redundant information, this is the solution I came up with, is there a better way that anyone can suggest? Perhaps something built in that I overlooked? Didn't have any luck with google.
Set<String> oldStringSet = getOldStringSet();
Set<String> newStringSet = getNewStringSet();
for(String currentString : oldStringSet)
{
if (!newStringSet.contains(currentString))
{
newStringSet.add(currentString);
}
}
Since a Set does not contain duplicate entries, you can therefore combine the two by:
newStringSet.addAll(oldStringSet);
It does not matter if you add things twice, the set will only contain the element once... e.g it's no need to check using contains method.
You can do it using this one-liner
Set<String> combined = Stream.concat(newStringSet.stream(), oldStringSet.stream())
.collect(Collectors.toSet());
With a static import it looks even nicer
Set<String> combined = concat(newStringSet.stream(), oldStringSet.stream())
.collect(toSet());
Another way is to use flatMap method:
Set<String> combined = Stream.of(newStringSet, oldStringSet).flatMap(Set::stream)
.collect(toSet());
Also any collection could easily be combined with a single element
Set<String> combined = concat(newStringSet.stream(), Stream.of(singleValue))
.collect(toSet());
The same with Guava:
Set<String> combinedSet = Sets.union(oldStringSet, newStringSet)
From the definition Set contain only unique elements.
Set<String> distinct = new HashSet<String>();
distinct.addAll(oldStringSet);
distinct.addAll(newStringSet);
To enhance your code you may create a generic method for that
public static <T> Set<T> distinct(Collection<T>... lists) {
Set<T> distinct = new HashSet<T>();
for(Collection<T> list : lists) {
distinct.addAll(list);
}
return distinct;
}
If you are using Guava you can also use a builder to get more flexibility:
ImmutableSet.<String>builder().addAll(someSet)
.addAll(anotherSet)
.add("A single string")
.build();
If you are using the Apache Common, use SetUtils class from org.apache.commons.collections4.SetUtils;
SetUtils.union(setA, setB);
Just use newStringSet.addAll(oldStringSet). No need to check for duplicates as the Set implementation does this already.
http://docs.oracle.com/javase/7/docs/api/java/util/Set.html#addAll(java.util.Collection)
Since sets can't have duplicates, just adding all the elements of one to the other generates the correct union of the two.
newStringSet.addAll(oldStringSet);
This will produce Union of s1 and s2
If you care about performance, and if you don't need to keep your two sets and one of them can be huge, I would suggest to check which set is the largest and add the elements from the smallest.
Set<String> newStringSet = getNewStringSet();
Set<String> oldStringSet = getOldStringSet();
Set<String> myResult;
if(oldStringSet.size() > newStringSet.size()){
oldStringSet.addAll(newStringSet);
myResult = oldStringSet;
} else{
newStringSet.addAll(oldStringSet);
myResult = newStringSet;
}
In this way, if your new set has 10 elements and your old set has 100 000, you only do 10 operations instead of 100 000.
Set.addAll()
Adds all of the elements in the specified collection to this set if they're not already present (optional operation). If the specified collection is also a set, the addAll operation effectively modifies this set so that its value is the union of the two sets
newStringSet.addAll(oldStringSet)

Categories

Resources