Common elements in two lists - java

I have two ArrayList objects with three integers each. I want to find a way to return the common elements of the two lists. Has anybody an idea how I can achieve this?

Use Collection#retainAll().
listA.retainAll(listB);
// listA now contains only the elements which are also contained in listB.
If you want to avoid that changes are being affected in listA, then you need to create a new one.
List<Integer> common = new ArrayList<Integer>(listA);
common.retainAll(listB);
// common now contains only the elements which are contained in listA and listB.

You can use set intersection operations with your ArrayList objects.
Something like this:
List<Integer> l1 = new ArrayList<Integer>();
l1.add(1);
l1.add(2);
l1.add(3);
List<Integer> l2= new ArrayList<Integer>();
l2.add(4);
l2.add(2);
l2.add(3);
System.out.println("l1 == "+l1);
System.out.println("l2 == "+l2);
List<Integer> l3 = new ArrayList<Integer>(l2);
l3.retainAll(l1);
System.out.println("l3 == "+l3);
Now, l3 should have only common elements between l1 and l2.
CONSOLE OUTPUT
l1 == [1, 2, 3]
l2 == [4, 2, 3]
l3 == [2, 3]

Why reinvent the wheel? Use Commons Collections:
CollectionUtils.intersection(java.util.Collection a, java.util.Collection b)

Using Java 8's Stream.filter() method in combination with List.contains():
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
/* ... */
List<Integer> list1 = asList(1, 2, 3, 4, 5);
List<Integer> list2 = asList(1, 3, 5, 7, 9);
List<Integer> common = list1.stream().filter(list2::contains).collect(toList());

consider two list L1 ans L2
Using Java8 we can easily find it out
L1.stream().filter(L2::contains).collect(Collectors.toList())

You can get the common elements between two lists using the method
"retainAll". This method will remove all unmatched elements from the list to
which it applies.
Ex.: list.retainAll(list1);
In this case from the list, all the elements which are not in list1 will be
removed and only those will be remaining which are common between list and
list1.
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(13);
list.add(12);
list.add(11);
List<Integer> list1 = new ArrayList<>();
list1.add(10);
list1.add(113);
list1.add(112);
list1.add(111);
//before retainAll
System.out.println(list);
System.out.println(list1);
//applying retainAll on list
list.retainAll(list1);
//After retainAll
System.out.println("list::"+list);
System.out.println("list1::"+list1);
Output:
[10, 13, 12, 11]
[10, 113, 112, 111]
list::[10]
list1::[10, 113, 112, 111]
NOTE: After retainAll applied on the list, the list contains common element between
list and list1.

List<String> lista =new ArrayList<String>();
List<String> listb =new ArrayList<String>();
lista.add("Isabella");
lista.add("Angelina");
lista.add("Pille");
lista.add("Hazem");
listb.add("Isabella");
listb.add("Angelina");
listb.add("Bianca");
// Create an aplusb list which will contain both list (list1 and list2) in which common element will occur twice
List<String> listapluslistb =new ArrayList<String>(lista);
listapluslistb.addAll(listb);
// Create an aunionb set which will contain both list (list1 and list2) in which common element will occur once
Set<String> listaunionlistb =new HashSet<String>(lista);
listaunionlistb.addAll(listb);
for(String s:listaunionlistb)
{
listapluslistb.remove(s);
}
System.out.println(listapluslistb);

public <T> List<T> getIntersectOfCollections(Collection<T> first, Collection<T> second) {
return first.stream()
.filter(second::contains)
.collect(Collectors.toList());
}

// Create two collections:
LinkedList<String> listA = new LinkedList<String>();
ArrayList<String> listB = new ArrayList<String>();
// Add some elements to listA:
listA.add("A");
listA.add("B");
listA.add("C");
listA.add("D");
// Add some elements to listB:
listB.add("A");
listB.add("B");
listB.add("C");
// use
List<String> common = new ArrayList<String>(listA);
// use common.retainAll
common.retainAll(listB);
System.out.println("The common collection is : " + common);

In case you want to do it yourself..
List<Integer> commons = new ArrayList<Integer>();
for (Integer igr : group1) {
if (group2.contains(igr)) {
commons.add(igr);
}
}
System.out.println("Common elements are :: -");
for (Integer igr : commons) {
System.out.println(" "+igr);
}

Some of the answers above are similar but not the same so posting it as a new answer.
Solution:
1. Use HashSet to hold elements which need to be removed
2. Add all elements of list1 to HashSet
3. iterate list2 and remove elements from a HashSet which are present in list2 ==> which are present in both list1 and list2
4. Now iterate over HashSet and remove elements from list1(since we have added all elements of list1 to set), finally, list1 has all common elements
Note: We can add all elements of list2 and in a 3rd iteration, we should remove elements from list2.
Time complexity: O(n)
Space Complexity: O(n)
Code:
import com.sun.tools.javac.util.Assert;
import org.apache.commons.collections4.CollectionUtils;
List<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
list1.add(3);
list1.add(4);
list1.add(5);
List<Integer> list2 = new ArrayList<>();
list2.add(1);
list2.add(3);
list2.add(5);
list2.add(7);
Set<Integer> toBeRemoveFromList1 = new HashSet<>(list1);
System.out.println("list1:" + list1);
System.out.println("list2:" + list2);
for (Integer n : list2) {
if (toBeRemoveFromList1.contains(n)) {
toBeRemoveFromList1.remove(n);
}
}
System.out.println("toBeRemoveFromList1:" + toBeRemoveFromList1);
for (Integer n : toBeRemoveFromList1) {
list1.remove(n);
}
System.out.println("list1:" + list1);
System.out.println("collectionUtils:" + CollectionUtils.intersection(list1, list2));
Assert.check(CollectionUtils.intersection(list1, list2).containsAll(list1));
output:
list1:[1, 2, 3, 4, 5]
list2:[1, 3, 5, 7]
toBeRemoveFromList1:[2, 4]
list1:[1, 3, 5]
collectionUtils:[1, 3, 5]

public static <T> List<T> getCommonElements(
java.util.Collection<T> a,
java.util.Collection<T> b
) {
if(a==null && b==null) return new ArrayList<>();
if(a!=null && a.size()==0) return new ArrayList<>(b);
if(b!=null && b.size()==0) return new ArrayList<>(a);
Set<T> set= a instanceof HashSet?(HashSet<T>)a:new HashSet<>(a);
return b.stream().filter(set::contains).collect(Collectors.toList());
}
For better time performance, please use HashSet (O(1) look up) instead of List(O(n) look ups)
Time complexity- O(b)
Space Complexity- O(a)

Below code
Remove common elements in the list
List<String> result = list1.stream().filter(item-> !list2.contains(item)).collect(Collectors.toList());
Retrieve common elements
List<String> result = list1.stream()
.distinct()
.filter(list::contains)
.collect(Collectors.toList());

The question talks about three items and many of the suggestions suggest using retainAll. I think it must be stated that as the size of the lists grown retainAll seems to become more inefficient.
In my tests I found that converting to Sets and looping is around 60 times faster than using retainAll for Lists with 1000s of items
List<Integer> common(List<Integer> biggerList, List<Integer> smallerList) {
Set<Integer> set1 = new HashSet<>(biggerList);
List<Integer> result = new ArrayList<>(smallerList.size());
for (Integer i : smallerList) {
if (set1.contains(i)) {
result.add(i);
}
}
return result;
}

Using Java 8 below solution
list1.stream()
.filter(list2::contains)
.collect(Collectors
.toList()));

Related

How can I verify that a list elements are in same order of another list or not?

list1 [1,2,3,4,5,6] --base list
list2 [1,2,4,3,6,5]
output: 4,6 are in incorrect order
I have to check the order should be as per list1. If not then i have to print all the elements which are not in correct order as per list1.
Stepping through the two lists and printing elements that are different is pretty simple, but it seems you only want to output differing elements once. For this you'd need to keep track of which you'd already seen, e.g. using a Set.
static void listCompare(List<Integer> list1, List<Integer> list2)
{
Set<Integer> seen = new HashSet<>();
int minLen = Math.min(list1.size(), list2.size());
for(int i=0; i<minLen; i++)
{
if(list1.get(i) != list2.get(i) && !seen.contains(list2.get(i)))
{
seen.add(list1.get(i));
System.out.format("%d (%d)%n", list2.get(i), list1.get(i));
}
}
}
Test:
List<Integer> list1 = Arrays.asList(1,2,3,4,5,6);
List<Integer> list2 = Arrays.asList(1,2,4,3,6,5);
listCompare(list1, list2);
Output:
4 (3)
6 (5)
You can compare value of list1 with list2 using list iterator and if compare result gives false then you can print value of list2.

How to prepend ArrayList to another ArrayList?

I am looking to prepend the elements of a java.util.ArrayList L1 to another java.util.ArrayList L2 and I cannot find an out of the box way to do it. I do not want to create a third ArrayList and hack around as L2 is the List being used in the view layer. Neither java.util.Collections nor org.apache.commons.collections.CollectionUtils has such a utility method (as far as I can see).
How can I efficiently prepend an ArrayList to another ArrayList, using existing API preferably ? For a java 7 environment.
P.S: addAll appends, I want to prepend.
Use List#addAll(int,Collection):
Inserts all of the elements in the specified collection into this list at the specified position (optional operation). Shifts the element currently at that position (if any) and any subsequent elements to the right (increases their indices). The new elements will appear in this list in the order that they are returned by the specified collection's iterator. The behavior of this operation is undefined if the specified collection is modified while the operation is in progress. (Note that this will occur if the specified collection is this list, and it's nonempty.)
If you use 0 as the index it will prepend the given Collection to the List. For example:
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
list1.add("Item #1");
list1.add("Item #2");
list2.add("Item #3");
list2.add("Item #4");
System.out.println("List #1: " + list1);
System.out.println("List #2: " + list2);
list2.addAll(0, list1);
System.out.println("Combined List: " + list2);
}
}
Output:
List #1: [Item #1, Item #2]
List #2: [Item #3, Item #4]
Combined List: [Item #1, Item #2, Item #3, Item #4]
subList gives you a view into a list. If you make a view at the very start of the list, addAll will do the right thing.
ArrayList<String> list = new ArrayList<String>(Arrays.asList("extant1", "extant2"));
ArrayList<String> prefix = new ArrayList<String>(Arrays.asList("prefix1", "prefix2"));
list.subList(0, 0).addAll(prefix);
list
// => list ==> [prefix1, prefix2, extant1, extant2]
Simply You can do this way:
List<String> l1 = new ArrayList<>();
List<String> l2 = new ArrayList<>();
l1.add("a");
l1.add("b");
l2.add("c");
l2.add("d");
l1.addAll(l2);
System.out.println(l1); // if you want result in list 1
l2.clear();
l2.addAll(l1);
System.out.println(l2); // if you want result in list 2
I don't see any particular inbuilt function that can do this thing. Here is the trick I am following to solve this.
If L1 is {1,2} and L2 is {3,4} then
Reverse the list L1 (It will become {2,1} )
Iterate the list L2 from back and add the
elements to L1. (You can also reverse L2 and do addAll on L1. If you
are ok with modifying L2, do it) (L1 will become {2,1,4,3} )
Reverse the list L1 (L1 will become {3,4,1,2} )
Total Time Complexity : O(m+n) where m is size of L1 and n is size of L2
List<Integer> li1 = new ArrayList<>();
li1.add(1);
li1.add(2);
List<Integer> li2 = new ArrayList<>();
li2.add(3);
li2.add(4);
Collections.reverse(li1);
ListIterator<Integer> listIterator = li2.listIterator(li2.size());
while (listIterator.hasPrevious())
{
Integer previous = listIterator.previous();
li1.add(previous);
}
Collections.reverse(li1);
System.out.println(li1);
If you don't want to use Collections.addAll​(int index, Collection c)
public static void main(String[] args) {
List<String> orginalList = new ArrayList<>(Arrays.asList( "E","F","G","H"));
System.out.println(orginalList);
Collections.reverse(orginalList);
List<String> newList = new ArrayList<>(Arrays.asList( "A","B","C","D"));
System.out.println(newList);
Collections.reverse(newList);
orginalList.addAll(newList);
Collections.reverse(orginalList);
System.out.println(orginalList);
}
Checking docs.oracle showed me one function. ArrayList.add(int index, E element) This helps, because you can place the items of the ArrayList at the beginning of the array, for example:
ArrayList <Integer> L1 = {2, 3, 5, 7} /*Imaginary declaration*/, L2 = {500, 600};
for(int i=0; i<L1.size(); i--) L2.add(0, L1.get(i));
But this will leave L2 with {7, 5, 3, 2, 500, 600} because each element added at index [0] will push the next ones forward. Instead, do it the opposite way:
for(int i=L1.size()-1; i>=0; i++) L2.add(0, L1.get(i));

Find duplicated items in a list with limited heap

There is an N + 1 length, read-only list of numbers between 1 and N.
There is a duplicate item in the list, but there may be more.
For Example N=3, items of the list [1,3,1,3]
I need an algorithm that prints the duplicated items.(doesn't matter how many times an item is in it)
Based on the example above, the result is 1,3
I need a solution in java that works with limeted heap(can run with many items in short time)
I've tried to create a new HashSet and add items from the list to the set, and if it already contains the item, I've saved it to an ArrayList.
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(1);
list.add(2);
list.add(5);
Set<Integer> set = new HashSet();
List<Integer> duplicatedList = new ArrayList<>();
for (Integer item : list) {
if(set.contains(item)) {
duplicatedList.add(item);
}
set.add(item);
}
System.out.println(duplicatedList +" "+ list);
It works, but i think this is not too effective. Is there a more efficient solution, for this problem?
If you want limited heap usage, remove non-duplicates from the original list, instead of creating a new list. Also use BitSet to track already seen numbers.
List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,1,2,5));
int N = list.size() - 1;
BitSet present = new BitSet(N);
for (Iterator<Integer> iter = list.iterator(); iter.hasNext(); ) {
int value = iter.next();
if (! present.get(value)) {
present.set(value);
iter.remove();
}
}
System.out.println(list);
Output
[1, 2]
If original list is read-only, build a new list like in question.
List<Integer> list = Arrays.asList(1,2,3,4,1,2,5);
BitSet present = new BitSet();
List<Integer> duplicatedList = new ArrayList<>();
for (Integer item : list) {
if (present.get(item))
duplicatedList.add(item);
else
present.set(item);
}
System.out.println(duplicatedList +" "+ list);
Output
[1, 2] [1, 2, 3, 4, 1, 2, 5]
The main improvement is the use of BitSet instead of Set<Integer>, relying on the fact that the range of numbers is limited to be between 1 and N, so the space used is lot less (except in extreme conditions).

Substituting in arraylists

I have an hash map, which maps integers to array of ArrayLists. For example, my data structure is the following:
7->((7,5,**4,3,1**),(7,6,4,3,1))
4->((4,2,1),(4,3,1))
Here, 7 is key, and arraylist e.g is (7,5,4,3,1), the array of arraylist in turn is ((7,5,4,3,1),(7,6,4,3,1))
4 is key, and arraylist e.g. is (4,2,1), the array of arraylist in turn is ((4,2,1),(4,3,1))
I wish to substitute the key values (in any given arraylist) and the values following it to create other arraylists, one example of this is given below:
7->((7,5,**4,2,1**),(7,6,4,2,1),(7,5,4,3,1),(7,6,4,3,1))
the thing I am not getting is how to obtain this substitution....to create bigger arraylists
the thing I am not getting is how to obtain this substitution....to create bigger arraylists..i know the datastructure..but want to create arraylists by substitution as given in subsequent example
Is there someway in java programming by which I may achieve this?
I am a novice at Java programming...I thought long about this but could not move it...can someone please help
HashMap<Integer,ArrayList<ArrayList<Integer>>> map;
map = new HashMap<Integer,ArrayList<ArrayList<Integer>>>();
EDIT: I've used 2 lines so that my answer could be more readable.
What actually do you want?
Is bellow code helpful?
Map<Integer, List<List<Integer>>> mapData = new HashMap<Integer, List<List<Integer>>>();
public void fillData(List<List<Integer>> lists)
{
// provide any kind of list of list
// e.g lists = {2,3,5,3}, {4,5,3,2}, {2,4,3}, {6,3,4}
for(List<Integer> list : lists)
{
int mapKey = list.get(0);
if(mapData.get(mapKey) == null)
{
// list of list will be null in first occurence of key(first element of list).
// create list of list and put tat in map.
List<List<Integer>> tempListOfList = new ArrayList<List<Integer>>();
tempListOfList.add(list);
mapData.put(mapKey, tempListOfList);
}
else
{
// from second occurence of same key.
// put list in the list of list of that key.
List<List<Integer>> listOfListInMap = mapData.get(mapKey);
listOfListInMap.add(list);
}
}
}
public List<List<Integer>> getListsByKey(int key)
{
// get list of list by mapKey
return mapData.get(key);
}
HashMap<Integer, ArrayList<ArrayList<Integer>>>.
below should do it:
Map<Integer, ArrayList <ArrayList<Integer>>> map = new hashMap<>();
Consider using a List of Lists and store this as part of a Map data structure. One possible way would be as follows:
Map<Integer,List<List<Integer>>> map = new HashMap<Integer, List<List<Integer>>>();
//How to add
List<List<Integer>> list = map.get(your_key);
if(list == null){ //This should be for the first time you're accessing the map with the key
list = new ArrayList<List<Integer>>();
}
//Create a inner list which will store the list of numbers
ArrayList<Integer> innerList = new ArrayList<Integer>();
innerList.add(integer_values);
//Add inner list to the list of lists
list.add(innerList);
//Finally put the list of list into the map with the key
map.put(your_key, list);
Edit: Assuming you know index of the list where you want to add new elements:
//Adding numbers to the inner list - assume you know the index
List<List<Integer>> list = map.get(key);
if(list == null || list.size() >= index){ //There's no list against the key or the size of the list is less then the index requested
return;
}
//Add new elements to the inner list
List<Integer> innerList = list.get(index);
innerList.add(your_new_int_values);
//Add inner list to the list of lists
list.add(innerList);
//Finally put the list of list into the map with the key
map.put(key, list);
You want to map integers to a list of lists of integers. This can be declared as:
Map<Integer, List<List<Integer>>> map = new HashMap<List<List<Integer>>>();
You can then put instances of ArrayList<List<Integer>> (or any other class that implements List) and for each such list of lists, you can add instances of ArrayList<Integer>.
You can then use the List.subList() method to put selected sublists into other entries in the map.
Say you have a list containing the two lists (7,5,4,3,1) and (7,6,4,3,1) stored under 7 and you want to construct the list of lists that should be stored under the key 4. You can do this:
List<List<Integer>> sevens = map.get(7);
List<List<Integer>> fours = new ArrayList<List<Integer>>();
for (List<Integer> aSevenList : sevens) {
int index = aSevenList.indexOf(4);
if (index >= 0) {
fours.add(aSevenList.subList(index, aSevenList.size()));
}
}
map.put(4, fours);
If you want to substitute one list as part of another, the following code fragment shows how that might be done:
int[] vals = { 7, 6, 5, 4, 3, 2, 1 };
List<Integer> list = new ArrayList<Integer>();
for (int val : vals) list.add(val);
List<Integer> sub = new ArrayList<Integer>();
sub.add(40);
sub.add(30);
sub.add(20);
System.out.println("Original list: " + list);
List<Integer> slice = list.subList(3, vals.length - 1);
slice.clear();
slice.addAll(sub);
System.out.println("Modified list: " + list);
This will generate the following output:
Original list: [7, 6, 5, 4, 3, 2, 1]
Modified list: [7, 6, 5, 40, 30, 20, 1]
Note that changes to a sublist are propagated to the original list.

Efficient intersection of two List<String> in Java?

Question is simple:
I have two List
List<String> columnsOld = DBUtils.GetColumns(db, TableName);
List<String> columnsNew = DBUtils.GetColumns(db, TableName);
And I need to get the intersection of these. Is there a quick way to achieve this?
You can use retainAll method:
columnsOld.retainAll (columnsNew);
Using Google's Guava library:
Sets.intersection(Sets.newHashSet(setA), Sets.newHashSet(setB))
Note: This is much more efficient than naively doing the intersection with two lists: it's O(n+m), versus O(n×m) for the list version. With two million-item lists it's the difference between millions of operations and trillions of operations.
Since retainAll won't touch the argument collection, this would be faster:
List<String> columnsOld = DBUtils.GetColumns(db, TableName);
List<String> columnsNew = DBUtils.GetColumns(db, TableName);
for(int i = columnsNew.size() - 1; i > -1; --i){
String str = columnsNew.get(i);
if(!columnsOld.remove(str))
columnsNew.remove(str);
}
The intersection will be the values left in columnsNew. Removing already compared values fom columnsOld will reduce the number of comparisons needed.
How about
private List<String> intersect(List<String> A, List<String> B) {
List<String> rtnList = new LinkedList<>();
for(String dto : A) {
if(B.contains(dto)) {
rtnList.add(dto);
}
}
return rtnList;
}
There is a nice way with streams which can do this in one line of code and you can two lists which are not from the same type which is not possible with the containsAll method afaik:
columnsOld.stream().filter(c -> columnsNew.contains(c)).collect(Collectors.toList());
An example for lists with different types. If you have a realtion between foo and bar and you can get a bar-object from foo than you can modify your stream:
List<foo> fooList = new ArrayList<>(Arrays.asList(new foo(), new foo()));
List<bar> barList = new ArrayList<>(Arrays.asList(new bar(), new bar()));
fooList.stream().filter(f -> barList.contains(f.getBar()).collect(Collectors.toList());
If you put the second list in a set say HashSet. And just iterate over the first list checking for presence on the set and removing if not present, your first list will eventually have the intersection you need.
It will be way faster than retainAll or contains on a list.
The emphasis here is to use a set instead of list. Lookups are O(1).
firstList.retainAll (new HashSet (secondList)) will also work.
using retainAll if don't care occurrences, otherwise using N.intersection
a = N.asList(12, 16, 16, 17, 19);
b = N.asList(16, 19, 107);
a.retainAll(b); // [16, 16, 19]
N.println(a);
a = N.asList(12, 16, 16, 17, 19);
b = N.asList(16, 19, 107);
a = N.intersect(a, b);
N.println(a); // [16, 19]
N is an utility class in abacus-common
use org.apache.commons.collections4.ListUtils#intersection
With Java 8 Stream API (and Java 9 List.of()) you can do following:
List<Integer> list1 = List.of(1, 1, 2, 2);
List<Integer> list2 = List.of(2, 2, 3, 3);
List<Integer> intersection = list1.stream()
.filter(list2::contains)
.distinct()
.collect(Collectors.toList());

Categories