Getting unique values from two arraylists with Collections - java

Looked several answers on stack, tried to do it with help of this one Simple way to compare 2 ArrayLists but can't try to figure out what seems to be a problem. To summarize the code that isnt visible, I've created two arraylists that contain 4 files names. Now im trying to get the third arraylist which will contain only unique values from these two arraylists.
Example: 1st arraylist - One, Two, Three, Four
2nd arraylist - One, Three, Five, Seven
3rd arraylist - Two, Four, Five, Seven (solution arraylist)
Here is the code:
Collection<String> filesFromDir = new
ArrayList(Arrays.asList(listOfFilenamesWithNoExtension));
Collection<String> filesFromDB = new ArrayList(Arrays.asList(listOfFilesDB));
List<String> listDir = new ArrayList<String>(filesFromDir);
List<String> listDB = new ArrayList<String>(filesFromDB);
listDir.removeAll(listDB);
listDB.removeAll(listDir);
System.out.println("Unique values: ");
System.out.println(listDir);
System.out.println(listDB);

Make a duplicate of the first list and use it to removeAll from second list. Because if you remove duplicates from first list and then compare it with second list all the values will be unique as the duplicates were already removed from first list.
Collection<String> listDir = new ArrayList(Arrays.asList("1","2", "3", "4", "5", "6", "7"));
Collection<String> listDirCopy = new ArrayList<>();
listDirCopy.addAll(listDir);
Collection<String> listDB = new ArrayList(Arrays.asList("1","3", "5", "7", "9"));
List<String> destinationList = new ArrayList<String>();
listDir.removeAll(listDB);
listDB.removeAll(listDirCopy);
destinationList.addAll(listDir);
destinationList.addAll(listDB);
System.out.println(destinationList);

You shouldn't use removeAll in this case:
listDir.removeAll(listDB);
listDB.removeAll(listDir);
Because once you remove the common element 'One' from listDir, the listDB still contains it and won't be removed by listDB.removeAll(listDir) because listDir doesn't contains it.
So you end up with listDB with it's original elements.
One possible solution would be to travers both list and check if an element is common.
Despite the lists are the same size you can travers them in the same loop.
for(int i=0;i<listDB.size();i++){
if(!listDB.contains(listDir.get(i)){
resultList.add(listDir.get(i))
}
if(!listDir.contains(listDB.get(i)){
resultList.add(listDB.get(i))
}
}

Hello sorry for my beginner code here but can you maybe make the third arraylist, loop through the first and then add all the elements in the first array list. Then loop through the second list and add the elements in the 3rd array list if it does not exist or remove if it exists.
Look at the following code, hope it helps
public void sort(ArrayList<String> one, ArrayList<String> two){
ArrayList<String> three = new ArrayList<>();
three.addAll(one);
for (int i = 0; i < two.size(); i++) {
if (three.contains(two.get(i))){
three.remove(two.get(i));
}else {
three.add(two.get(i));
}
}
}

Related

Remove duplicates from two lists

I have two lists of Strings and am removing duplicates like this:
List<String> list1 = Arrays.asList("1", "2", "3", "4");
List<String> list2 = Arrays.asList("1", "4", "5", "6");
List<String> duplicates = list1.stream().filter(s -> list2.contains(s)).collect(Collectors.toList());
list1.removeAll(duplicates);
list2.removeAll(duplicates);
So the result is:
list1 = 2, 3
list2 = 5, 6
Is there a better way to accomplish this? i.e. with fewer statements.
You can use removeAll which is defined in Collection interface.
boolean removeAll(Collection<?> c)
Removes all of this collection's elements that are also contained in
the specified collection (optional operation). After this call
returns, this collection will contain no elements in common with the
specified collection.
// init
List<String> sourceList1 = Arrays.asList("1", "2", "3", "4");
List<String> sourceList2 = Arrays.asList("1", "4", "5", "6");
// you need to create duplicate collection, because removeAll modify collection
List<String> resultList1 = new ArrayList(sourceList1);
List<String> resultList2 = new ArrayList(sourceList2);
//remove duplicates from collections
resultList1.removeAll(sourceList2); // second from first
resultList2.removeAll(sourceList1); // first from second
One of the possibilities worth considering is to create Set<String> and add these lists to it. Set allows adding only unique values to itself, it prevents adding duplicates.
The first way to use Set: Create a Set containing an intersection of both lists. Adding to new, getting rid of duplicates lists is taking place only if you checked that every object of the source is not present in previously created Set of duplicates.
Second way (only if your lists doesn't care about holding duplicates itself - for example in the first you have two times the same value existing): Create a Set for the first and for the second list, and add these lists to them and after that check for duplicates.
As I mentioned in comments I could misunderstood question and looked for "another", not for "more efficient" way of achieving what you're asking for, but maybe it could actually be helpful nonetheless.

Converting List<List<String>> to array

I have elements that is declared in a list variable such as:
List<List<String>> textList = new ArrayList<>();
The elements are added such as:
textList.add(Arrays.asList(p)); //adding elements
The only way I could output the elements inside the variable is by using:
for(List<String> s: textList){
System.out.println(s); }
which output elements like this:
[He is a boy.]
[He likes apple.]
[She is a girl.]
Now, I would like to store them in an array so that the elements will look like this when outputted.
[He is a boy., He likes apple., She is a girl.]
I've tried
String[] textArr = new String[textList.size()];
textArr = textList.toArray(textArr);
for(String s : textArr){
System.out.println(s);}
but I got an error about:
Exception in thread "main" java.lang.ArrayStoreException
at java.lang.System.arraycopy(Native Method)
at java.util.Arrays.copyOf(Arrays.java:3213)
at java.util.ArrayList.toArray(ArrayList.java:407)
So, how do I convert the elements inside a list into array using the proper way. Thanks!
Your problem is that you are not storing Strings in your list textList.
textList.add(Arrays.asList(p));
As the type says, you have a List of List of String here.
So you can't take the elements of that list and assume they are Strings. Because they aren't! The error message tells you that: toArray() wants strings it can put into that array of strings, but you give it a List of List of String!
But thing is: what you are describing here doesn't make sense in the first place. Printing strings shouldn't care if strings are in an array or a List.
What I mean is: when you manually iterate a List or an array to print its content, then it absolutely doesn't matter if you iterate a List or an array. The code is even the same:
for (String someString : someCollection) {
System.out.println(someString);
}
someCollection can be both: array or List!
In other words: the idea to turn data that is nicely stored within Lists into arrays for printing simply doesn't make any sense. To the contrary: you are probably calling toString() on your List object, and the result of that ... isn't 100% what you want. But I guarantee you: calling toString() on some array will result in something you totally will not want.
Long story short: forget about converting to Arrays; simply iterate your List of List of Strings and use a StringBuilder to collect the content of that collection the way you want to see it (you simply append those [ ] chars to that builder in those places you want them to see).
(if you insist on that conversion to array, the key point there to understand is that only a List of String can be turned into an array of string. So a List of List ... doesnt work that easy).
Using streams and flatMap, you can do this:
List<List<String>> list = ...;
String[] strings = list.stream().flatMap(l -> l.stream()).collect(Collectors.toList()).toArray(new String[0]);
This is equivalent to using a loop (You can use two nested for loops as suggested in the comments instead by replacing the addAll, but why?):
List<List<String>> list = ...;
List<String> stringList = new ArrayList<>();
for (List<String> l : list)
stringList.addAll(l);
String[] strings = list.toArray(new String[stringList.size()]);
You can use Iterator in order to go over every element of the list, instance of the for each statement (I personally like the iterators more). The code you could use would be something like
//Your list
List<List<String>> textList = new ArrayList<>();
//The iterators
Iterator<List<String>> itList = textList.iterator();
Iterator<String> itString;
//The string to store the phrases
String s[] = new String[textList.size()];
int i =0;
//First loop, this seeks on every list of lists
while(itList.hasNext()){
//Getting the iterator of strings
itString = itList.next().iterator();
s[i] = "";
//2nd loop, it seeks on every List of string
while(itString.hasNext()){
s[i] = s[i].concat(itString.next());
}
s[i] = s[i].concat(".");
i++;
}

How do I add non-existing values in from arrayList2 to arrayList1?

Let's say I have an arrayList1 of Points. The data structure is like this :
(1,2)->(2,2)->(3,2)->(4,2)->(5,2)
I have another arrayList2 of Points :
(2,2)->(1,2)->(8,5)->(9,3)
How do I compare the two lists and add non-existing values from arrayList2 to arrayList1?
current solution
The only method I can think of now is using a for loop to compare each of the Points in arrayList1 such as, if(!arrayList1.contains(arrayList2.get(i))){ arrayList1.add(arrayList2.get(i)); } i++;.
Is there a more efficient way or already prepared method from a class? Because I have arrayList1 until arrayList6 to compare and replace....
For one-liner lovers (running demo):
List<Point> list3 = new ArrayList<Point>(new HashSet<Point>(list1){{ addAll(list2); }});
Safe version * (running demo):
Set<String> tmpSet = new HashSet<String>(arrayList1);
tmpSet.addAll(arrayList2);
List<String> mergedList = new ArrayList<String>(tmpSet);
* As correctly pointed out by Bruce Wayne, Double Brace initialization (the one-liner example, also used in both examples to populate the first two lists) should be used with care, due to the potential drawbacks described in the following article:
Don’t be “Clever”: The Double Curly Braces Anti Pattern
Explanation: Sets can't contain duplicates, so use one as transition vector.
Example 1 code:
List<String> arrayList1 = new ArrayList<String>(){{ add("One"); add("Two"); }};
List<String> arrayList2 = new ArrayList<String>(){{ add("Two"); add("Three"); }};
List<String> mergedList = new ArrayList<String>(new HashSet<String>(arrayList1){{ addAll(arrayList2); }});
System.out.println(mergedList);
Output: [One, Two, Three]
Example 2 code:
List<String> arrayList1 = new ArrayList<String>(){{ add("One"); add("Two"); }};
List<String> arrayList2 = new ArrayList<String>(){{ add("Two"); add("Three"); }};
Set<String> tmpSet = new HashSet<String>(arrayList1);
tmpSet.addAll(arrayList2);
List<String> mergedList = new ArrayList<String>(tmpSet);
System.out.println(mergedList);
Output: [One, Two, Three]
If time complexity is your main priority, add all the points in List1 to a HashSet<Point>.
Then, for each list thereafter, loop through it and see if the set contains each point and if not, add it to List1.
Set<Point> pointsInList1 = new HashSet<>(list1);
for(Point p : list2)
{
if(!pointsInList1.contains(p)) {
list1.add(p);
pointsInList1.add(p);
}
}
//Repeat for other lists
This solution is linear with respect to the size of the largest list.
It can have multiple solutions. As you are using java.awt.Point class which already has equals method overridden(based on the coordinates).
So, you can easily use contains method of List class.
for(Point point : list2){
if(!list1.contains(point)){
list1.add(point);
}
}
Make sure to use for each loop for a better performance (Do not use index based loop (It makes a difference if you are using LinkedList)).
ii) Another alternative is to use java.util.Set and use its method addAll(Set). As Set does not all duplicates and hence will merge the elements efficiently.
You should use a Set. It is a collection with no duplicates. So you can add the same value twice, it will be present only one time.
It means you can add many List in your Set, you will not have duplicates in it.
Set setA = new HashSet();
ArrayList<Point> points1 = new ArrayList<Point>();
ArrayList<Point> points2 = new ArrayList<Point>();
Point element1 = new Point(0,0);
Point element2 = new Point(0,1);
Point element3 = new Point(0,0);
Point element4 = new Point(0,2);
points1.add(element1);
points1.add(element2);
points1.add(element3);
points2.add(element1);
points2.add(element4);
setA.addAll(points1);
setA.addAll(points2);
Iterator<Point> it = setA.iterator();
while(it.hasNext())
System.out.println(it.next());
Output :
java.awt.Point[x=0,y=0]
java.awt.Point[x=0,y=1]
java.awt.Point[x=0,y=2]
You can do something like this
list2.removeAll(list1);
list1.addAll(list2);
You have to override your equal function in your Point Class
and then you could iterate over these two list, and compare their values.
How do I compare the two lists
That one is easy, just use equals.
add non-existing values from arrayList2 to arrayList1
remove all elements of arrayList1 from arrayList2 and add it to the arrayList2. That way only the new elements will be added to arrayList2
get the difference (arrayList1 - arrayList2) and add these to arrayList2 (for instance with CollectionUtils)
Your current solution is probably wrong (it will either skip one element or run forever, depending on your loop):
if(arrayList1.contains(arrayList2.get(i))) {
i++; // this shouldn't be there if done in the loop
} else {
arrayList1.add(arrayList2.get(i)); // here a ++ is needed if not in the loop
}
Is there a more efficient way
A little advice:
First, make it work (and have a good UnitTest coverage). Then (and only then!) optimize if needed!

add ArrayList to multiple ArrayList in java

Hi i have problem with ArrayLists i have 3 lists
ArrayList1<Integer>=[1,2,3]
ArrayList2<Integer>=[]
ArrayList3<ArrayList<Integer>>=[]
ArrayList1 elements are used for adding values to ArrayList2
for example
for(int i:ArrayList1)
{
for(int a=0;a<i;a++)
{
ArrayList2.add(a);
}
}
and that works fine no problem there but now i want to for every element in ArrayList1 to add ArrayList2 to ArrayList3 this is what I have come up with but it does not work
for(int i:ArrayList1)
{
for(int a=0;a<i;a++)
{
ArrayList2.add(a);
}
ArrayList3.add(ArrayList2);
}
Simply use addAll, and Collections.fill.
Example
list2.addAll(list1);
list3 = new ArrayList<ArrayList<Integer>>(list1.size());
Collections.fill(list3, list2);
Note that list3 will be filled with the same instance of list2.
This means that every change to list2 will be reflected in each element of list3.
If this is not the behavior you're expecting, iterate over the length of list1 and add a new ArrayList<Integer>(list2).
for(int a=0;a<i;a++)
is wrong. You must not stop at a < i, it makes no sense! You want to add the whole arrayList2 to ArrayList3, not a number of integers equal to the value of the int i in ArrayList1.

adding two arraylists into one

I want to check branchList whether has same element or not, if same put branchList and tglList element separate arraylist and put that arraylist into another arraylist,
The result I want is BranchList1 have 2 arraylist where 1st arraylist contain for element '1' and 2nd arraylist contain element '2' and TglList1 have 2 arraylist as element, but what i get is both 1st and 2nd array get same value.
How can this be done?
ArrayList branchList = new ArrayList();
branchList.add("1");
branchList.add("1");
branchList.add("1");
branchList.add("2");
branchList.add("2");
branchList.add("2");
ArrayList tglList = new ArrayList();
tglList.add("5");
tglList.add("10");
tglList.add("20");
tglList.add("100");
tglList.add("500");
tglList.add("1000");
ArrayList newBranchList = new ArrayList();
ArrayList newTglList = new ArrayList();
ArrayList BranchList1 = new ArrayList();
ArrayList TglList1 = new ArrayList();
ArrayList abc = new ArrayList();
String checkBranch = new String();
for(int i=0;i<branchList.size();i++){
String branch = branchList.get(i).toString();
if(i==0 || checkBranch.equals(branch)){
newBranchList.add(branch);
newTglList.add(tglList.get(i).toString());
}else{
BranchList1.add(newBranchList);
TglList1.add(newTglList);
newBranchList.clear();
newTglList.clear();
newBranchList.add(branch);
newTglList.add(tglList.get(i).toString());
}
if(i==(branchList.size()-1)){
BranchList1.add(newBranchList);
TglList1.add(newTglList);
}
checkBranch = branch;
}
}
so expected result is as below:
BranchList1 = [ [1,1,1],[2,2,2]]
TglList1 = [[5,10,20],[50,100,200]]
but what I get is
BranchList1 = [ [2,2,2],[2,2,2]]
TglList1 = [[50,100,200],[50,100,200]]
How can I modify the code
I didn't thoroughly read through your code (and I don't quite get what you're asking for), but if you want to merge (add the elements of) branchList and tglList to TglList1, try this:
TglList1.addAll(branchList);
TglList1.addAll(tglList);
After that, TglList1 should contain all elements of both lists. If you need the list to be sorted, you might want to call Collections.sort(TglList1) afterwards (just note that sorting strings might place "100" before "2", due to "1" being lexically smaller than "2").

Categories

Resources