Get differences between two arrayList but compare them in uppercase - java

I have two arrayList and I need to compare them, get the values that are uniques and build a new array with them, problem is some of the values are the same but in uppercase so they shouldn't show as unique value. This is my code alredy, works but is to slow
for (i = 0; i < parsedLocal.size(); i++) {
for (j = 0; j < parsedRemote.size(); j++) {
if (parsedLocal[i].toUpperCase().equals(parsedRemote[j].toUpperCase())){
parsedLocal.remove(parsedLocal[i])
}
}
}
Then I found this solution that is faster but doesn't compare uppercases or lowercases, any idea on how to do that with that method or similar?
parsedLocal.removeAll(parsedRemote);

The following groovy code should compute the difference (note that the returned collection will contain upper-case values):
parsedLocal*.toUpperCase() - parsedRemote*.toUpperCase()
But you can also use a stream-based computation. This has a slightly higher space complexity, but should have linear time complexity:
Set<String> set1 = parsedLocal.stream()
.map{it.toUpperCase()}
.collect(Collectors.toSet());
List<String> retained = parsedRemote.stream()
.filter{!set1.contains(it.toUpperCase())}
.collect(Collectors.toList());

Using removeIf can be easy in java 8 as follows:
List<String> parsedLocal = new ArrayList();
parsedLocal.add("aa");
parsedLocal.add("bb");
List<String> parsedRemote = new ArrayList();
parsedRemote.add("AA");
List<String> tmpList = new ArrayList<>(parsedLocal);
for (String s : parsedRemote) {
tmpList.removeIf((t) -> t.equalsIgnoreCase(s));
}
System.out.println(tmpList);
And the output:
[bb]

Related

Iterate over one collection and get the same index value of another collection

I want know is it even possible in Java to iterate over, let say a list, and get/set the same index(int) value of other list?
for (Response e : responseList) {
e.setPrimarySkills(requestList.get(??).getPrimarySkills());
}
Since it can't be done through model mapper because of the issues, is there any neat way of doing the same ?
Using two iterators:
Iterator<Response> responseIt = responseList.iterator();
Iterator<Request> requestIt = requestList.iterator();
while(responseIt.hasNext() && requestIt.hasNext()) {
Response response = responseIt.next();
Request request = requestIt.next();
...
}
[Recommended for its clarity]
Using Guava Streams.forEachPair :
Streams.forEachPair(
requestList.stream(),
responseList.stream(),
(req, resp) -> resp.setPrimarySkills(req.getPrimarySkills())
);
Either, don't do it with a for-each loop, use an indexed for loop.
for (int i = 0; i < responseList.size(); ++i) {
responseList.get(i).setPrimarySkills(requestList.get(i).getPrimarySkills());
}
Or, use a pair of Iterators:
Iterator<Response> responseIt = responseList.iterator();
Iterator<Request> requestIt = requestList.iterator();
while (responseIt.hasNext() && requestIt.hasNext()) {
// Put responseIt.next() and requestIt.next() into variables, if you want.
responseIt.next().setPrimarySkills(requestIt.next().getPrimarySkills());
}
The advantage of Iterators over an index is that Iterators are efficient for non-RandomAccess lists; but, unless your lists are big, it's unlikely to be a significant (or even noticable) difference.
You can do it with a for-each loop, by maintaining the index yourself, but it's a bit inconsistent in the treatment of the two lists:
int i = 0;
for (Response e : responseList) {
e.setPrimarySkills(requestList.get(i).getPrimarySkills());
i++;
}
You can use a for-loop with incrementing index:
List<String> l1 = List.of("a", "b");
List<Integer> l2 = List.of(1, 2);
for(int i=0; i<l1.size(); i++) {
String s = l1.get(i);
Integer i = l2.get(i);
}
Of course you should first make sure that both lists have equal length, to avoid OutOfBounds Exception.

Best way to get unique list without changing the Order

I have a list of string or list of integers of 20,000 items
Now it contains duplicates...However i don't want to disturb the order of the item.
We can easily convert a list to Set for unique Set unique = new HashSet(list);
However the above breaks the sequential order of the items.
What would be the best approach for this?
Thanks.
You should use java.util.LinkedHashSet to get unique elements without changing the order:
Set<String> uniqueSet = new LinkedHashSet<>(list);
One other way is to use distinct():
list.stream().distinct().collect(Collectors.toList())
But distinct() uses LinkedHashSet internally. There is no need for unnecessary procedure.
So best way is using the LinkedHashSet constructor:
LinkedHashSet(Collection c) Constructs a new linked hash
set with the same elements as the specified collection.
You can try stream distinct
yourList.stream().distinct().collect(Collectors.toList());
Update1:
As I know, this is the best solution.
list.contains(element) will do 2 loop processes. One for iterate the element and add it to new list, one for check element is contained -> 0(n*n)
new LinkedHashSet() will created a new LinkedHashSet, and a new Arraylist output -> issue about memory. And the performance, i think it is equals with stream distinct
Update2: we must ensure that the output is a List, not a Set
As I know, stream distinct use HashSet internally. It is an more efficient memory implementation than LinkedHashSet (which is hash table and linked list implementation of the set interface) in our case.
Detail here
If you apply LinkedHashSet, the source code will something like below, so we have 1 ArrayList and 1 LinkedHashSet.
output = new ArrayList(new LinkedHashSet(yourList));
I did a small benchmark with 1k for-loop.
int size = 1000000;
Random rand = new Random((int) (System.currentTimeMillis() / 1000));
List<Integer> yourList = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
yourList.add(rand.nextInt(10000));
}
// test1: LinkedHashSet --> 35ms
new ArrayList<Integer>(new LinkedHashSet<Integer>(yourList));
// test2: Stream distinct --> 30ms
yourList.stream().distinct().collect(Collectors.toList());
If you don't want to break the order, then Iterate the list and make a new list as below.
ArrayList<Integer> newList = new ArrayList<Integer>();
for (Integer element : list) {
if (!newList.contains(element)) {
newList.add(element);
}
}
Try the bellow code
public static void main(String[] args) {
String list[] = {"9","1","1","9","2","7","2"};
List<String> unique = new ArrayList<>();
for(int i=0; i<list.length; i++) {
int count = unique.size();
if(count==0) {
unique.add(list[i]);
}else {
boolean available = false;
for(int j=0; j<count; j++) {
if(unique.get(j).equals(list[i])) {
available = true;
break;
}
}
if(!available) {
unique.add(list[i]);
}
}
}
//checking latest 'unique' value
for(int i=0; i<unique.size(); i++) {
System.out.println(unique.get(i));
}
}
It will return 9 1 2 7, but I haven't tried up to 20,000 collection lists, hopefully there are no performance issues
If you are trying to eliminate duplicates, you can use LinkedHashSet it will maintain the order.
if String
Set<String> dedupSet = new LinkedHashSet<>();
if Integer
Set<Integer> dedupSet = new LinkedHashSet<>();

How to parse a string when compared to another string?

In Java, I want to extract the differences from one comma-separated string when compared to another.
e.g
The string I want to extract the differences from: 1,hello,fire,dog,green
The string I am comparing with : 1,hello,water,dog,yellow
So the result of the function would give me a arraylist of [3,fire] and[5,green] as those items are different than the items in the second string, which are 'water' and 'yellow'. The numbers are the index positions of each item detected to be a difference. The other items match and are not considered.
First, you can create your own Pair class (based on Creating a list of pairs in java), doesn't have to be template.
Then Do something like this:
Split the two strings:
List<String> toCompareSplit= Arrays.asList(toCompare.split(","));
List<String> compareWithSplit= Arrays.asList(compareWith.split(","));
Iterate the lists:
List<Pair> diffList= new ArrayList<Pair>();
for (int i= 0; i < toCompareSplit.size; i++){
if (!toCompareSplit.get(i).equals(compareWithSplit.get(i))){
Pair pair= new Pair(i+1, toCompareSplit.get(i));
diffList.add(pair);
}
}
If the lists aren't in the same size you can run to the end of the shortest one etc.
Why not just loop through by splitting the strings.
public static List<String> compareStrings(String str1, String str2) {
String[] arrStr1 = str1.split(",");
String[] arrStr2 = str2.split(",");
List<String> strList = new ArrayList<String>();
for(int index = 0; index < arrStr1.length; ++index) {
if (!arrStr1[index].equals(arrStr2[index])) {
strList.add("[" + index + "," + arrStr1[index] + "]");
}
}
return strList;
}
Beaware of index out of bounds exception..!!
var left = "1,hello,fire,dog,green";
var right = "1,hello,water,dog,yellow";
var result = left.Split(',').Zip(right.Split(','), Tuple.Create).Where(x => x.Item1 != x.Item2).ToArray();
Using C#, this will return an array of tuples of the different elements. Sorry I don't have a compiler to hand so may be some small syntax errors in there.

Removing Duplicate Values from ArrayList

I have one Arraylist of String and I have added Some Duplicate Value in that. and i just wanna remove that Duplicate value So how to remove it.
Here Example I got one Idea.
List<String> list = new ArrayList<String>();
list.add("Krishna");
list.add("Krishna");
list.add("Kishan");
list.add("Krishn");
list.add("Aryan");
list.add("Harm");
System.out.println("List"+list);
for (int i = 1; i < list.size(); i++) {
String a1 = list.get(i);
String a2 = list.get(i-1);
if (a1.equals(a2)) {
list.remove(a1);
}
}
System.out.println("List after short"+list);
But is there any Sufficient way remove that Duplicate form list. with out using For loop ?
And ya i can do it by using HashSet or some other way but using array list only.
would like to have your suggestion for that. thank you for your answer in advance.
You can create a LinkedHashSet from the list. The LinkedHashSet will contain each element only once, and in the same order as the List. Then create a new List from this LinkedHashSet. So effectively, it's a one-liner:
list = new ArrayList<String>(new LinkedHashSet<String>(list))
Any approach that involves List#contains or List#remove will probably decrease the asymptotic running time from O(n) (as in the above example) to O(n^2).
EDIT For the requirement mentioned in the comment: If you want to remove duplicate elements, but consider the Strings as equal ignoring the case, then you could do something like this:
Set<String> toRetain = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
toRetain.addAll(list);
Set<String> set = new LinkedHashSet<String>(list);
set.retainAll(new LinkedHashSet<String>(toRetain));
list = new ArrayList<String>(set);
It will have a running time of O(n*logn), which is still better than many other options. Note that this looks a little bit more complicated than it might have to be: I assumed that the order of the elements in the list may not be changed. If the order of the elements in the list does not matter, you can simply do
Set<String> set = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
set.addAll(list);
list = new ArrayList<String>(set);
if you want to use only arraylist then I am worried there is no better way which will create a huge performance benefit. But by only using arraylist i would check before adding into the list like following
void addToList(String s){
if(!yourList.contains(s))
yourList.add(s);
}
In this cases using a Set is suitable.
You can make use of Google Guava utilities, as shown below
list = ImmutableSet.copyOf(list).asList();
This is probably the most efficient way of eliminating the duplicates from the list and interestingly, it preserves the iteration order as well.
UPDATE
But, in case, you don't want to involve Guava then duplicates can be removed as shown below.
ArrayList<String> list = new ArrayList<String>();
list.add("Krishna");
list.add("Krishna");
list.add("Kishan");
list.add("Krishn");
list.add("Aryan");
list.add("Harm");
System.out.println("List"+list);
HashSet hs = new HashSet();
hs.addAll(list);
list.clear();
list.addAll(hs);
But, of course, this will destroys the iteration order of the elements in the ArrayList.
Shishir
Java 8 stream function
You could use the distinct function like above to get the distinct elements of the list,
stringList.stream().distinct();
From the documentation,
Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.
Another way, if you do not wish to use the equals method is by using the collect function like this,
stringList.stream()
.collect(Collectors.toCollection(() ->
new TreeSet<String>((p1, p2) -> p1.compareTo(p2))
));
From the documentation,
Performs a mutable reduction operation on the elements of this stream using a Collector.
Hope that helps.
Simple function for removing duplicates from list
private void removeDuplicates(List<?> list)
{
int count = list.size();
for (int i = 0; i < count; i++)
{
for (int j = i + 1; j < count; j++)
{
if (list.get(i).equals(list.get(j)))
{
list.remove(j--);
count--;
}
}
}
}
Example:
Input: [1, 2, 2, 3, 1, 3, 3, 2, 3, 1, 2, 3, 3, 4, 4, 4, 1]
Output: [1, 2, 3, 4]
List<String> list = new ArrayList<String>();
list.add("Krishna");
list.add("Krishna");
list.add("Kishan");
list.add("Krishn");
list.add("Aryan");
list.add("Harm");
HashSet<String> hs=new HashSet<>(list);
System.out.println("=========With Duplicate Element========");
System.out.println(list);
System.out.println("=========Removed Duplicate Element========");
System.out.println(hs);
I don't think the list = new ArrayList<String>(new LinkedHashSet<String>(list)) is not the best way , since we are using the LinkedHashset(We could use directly LinkedHashset instead of ArrayList),
Solution:
import java.util.ArrayList;
public class Arrays extends ArrayList{
#Override
public boolean add(Object e) {
if(!contains(e)){
return super.add(e);
}else{
return false;
}
}
public static void main(String[] args) {
Arrays element=new Arrays();
element.add(1);
element.add(2);
element.add(2);
element.add(3);
System.out.println(element);
}
}
Output:
[1, 2, 3]
Here I am extending the ArrayList , as I am using the it with some changes by overriding the add method.
public List<Contact> removeDuplicates(List<Contact> list) {
// Set set1 = new LinkedHashSet(list);
Set set = new TreeSet(new Comparator() {
#Override
public int compare(Object o1, Object o2) {
if(((Contact)o1).getId().equalsIgnoreCase(((Contact)2).getId()) ) {
return 0;
}
return 1;
}
});
set.addAll(list);
final List newList = new ArrayList(set);
return newList;
}
This will be the best way
List<String> list = new ArrayList<String>();
list.add("Krishna");
list.add("Krishna");
list.add("Kishan");
list.add("Krishn");
list.add("Aryan");
list.add("Harm");
Set<String> set=new HashSet<>(list);
It is better to use HastSet
1-a) A HashSet holds a set of objects, but in a way that it allows you to easily and quickly determine whether an object is already in the set or not. It does so by internally managing an array and storing the object using an index which is calculated from the hashcode of the object. Take a look here
1-b) HashSet is an unordered collection containing unique elements. It has the standard collection operations Add, Remove, Contains, but since it uses a hash-based implementation, these operation are O(1). (As opposed to List for example, which is O(n) for Contains and Remove.) HashSet also provides standard set operations such as union, intersection, and symmetric difference.Take a look here
2) There are different implementations of Sets. Some make insertion and lookup operations super fast by hashing elements. However that means that the order in which the elements were added is lost. Other implementations preserve the added order at the cost of slower running times.
The HashSet class in C# goes for the first approach, thus not preserving the order of elements. It is much faster than a regular List. Some basic benchmarks showed that HashSet is decently faster when dealing with primary types (int, double, bool, etc.). It is a lot faster when working with class objects. So that point is that HashSet is fast.
The only catch of HashSet is that there is no access by indices. To access elements you can either use an enumerator or use the built-in function to convert the HashSet into a List and iterate through that.Take a look here
Without a loop, No! Since ArrayList is indexed by order rather than by key, you can not found the target element without iterate the whole list.
A good practice of programming is to choose proper data structure to suit your scenario. So if Set suits your scenario the most, the discussion of implementing it with List and trying to find the fastest way of using an improper data structure makes no sense.
public static void main(String[] args) {
#SuppressWarnings("serial")
List<Object> lst = new ArrayList<Object>() {
#Override
public boolean add(Object e) {
if(!contains(e))
return super.add(e);
else
return false;
}
};
lst.add("ABC");
lst.add("ABC");
lst.add("ABCD");
lst.add("ABCD");
lst.add("ABCE");
System.out.println(lst);
}
This is the better way
list = list.stream().distinct().collect(Collectors.toList());
This could be one of the solutions using Java8 Stream API. Hope this helps.
public void removeDuplicates() {
ArrayList<Object> al = new ArrayList<Object>();
al.add("java");
al.add('a');
al.add('b');
al.add('a');
al.add("java");
al.add(10.3);
al.add('c');
al.add(14);
al.add("java");
al.add(12);
System.out.println("Before Remove Duplicate elements:" + al);
for (int i = 0; i < al.size(); i++) {
for (int j = i + 1; j < al.size(); j++) {
if (al.get(i).equals(al.get(j))) {
al.remove(j);
j--;
}
}
}
System.out.println("After Removing duplicate elements:" + al);
}
Before Remove Duplicate elements:
[java, a, b, a, java, 10.3, c, 14, java, 12]
After Removing duplicate elements:
[java, a, b, 10.3, c, 14, 12]
Using java 8:
public static <T> List<T> removeDuplicates(List<T> list) {
return list.stream().collect(Collectors.toSet()).stream().collect(Collectors.toList());
}
In case you just need to remove the duplicates using only ArrayList, no other Collection classes, then:-
//list is the original arraylist containing the duplicates as well
List<String> uniqueList = new ArrayList<String>();
for(int i=0;i<list.size();i++) {
if(!uniqueList.contains(list.get(i)))
uniqueList.add(list.get(i));
}
Hope this helps!
private static void removeDuplicates(List<Integer> list)
{
Collections.sort(list);
int count = list.size();
for (int i = 0; i < count; i++)
{
if(i+1<count && list.get(i)==list.get(i+1)){
list.remove(i);
i--;
count--;
}
}
}
public static List<String> removeDuplicateElements(List<String> array){
List<String> temp = new ArrayList<String>();
List<Integer> count = new ArrayList<Integer>();
for (int i=0; i<array.size()-2; i++){
for (int j=i+1;j<array.size()-1;j++)
{
if (array.get(i).compareTo(array.get(j))==0) {
count.add(i);
int kk = i;
}
}
}
for (int i = count.size()+1;i>0;i--) {
array.remove(i);
}
return array;
}
}

How to move data from multiple Arraylist to multiple Arrays (in Java)

I have 3 arraylist each have size = 3 and 3 arrays also have length = 3 of each. I want to copy data from arraylists to arrays in following way but using any loop (i.e for OR for each).
myArray1[1] = arraylist1.get(1);
myArray1[2] = arraylist2.get(1);
myArray1[3] = arraylist3.get(1);
I have done it manually one by one without using any loop, but code appears to be massive because in future I'm sure that number of my arraylists and arrays will increase up to 15.
I want to copy the data from arraylists to arrays as shown in the image but using the loops not manually one by one?
How about this?
List<Integer> arraylist0 = Arrays.asList(2,4,3);
List<Integer> arraylist1 = Arrays.asList(2,5,7);
List<Integer> arraylist2 = Arrays.asList(6,3,7);
List<List<Integer>> arraylistList = Arrays.asList(arraylist0, arraylist1, arraylist2);
int size = 3;
int[] myArray0 = new int[size];
int[] myArray1 = new int[size];
int[] myArray2 = new int[size];
int[][] myBigArray = new int[][] {myArray0, myArray1, myArray2};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
myBigArray[i][j] = arraylistList.get(j).get(i);
}
}
To explain, since we want to be able to work with an arbitrary size (3, 15, or more), we are dealing with 2-dimensional data.
We are also dealing with array and List, which are slightly different in their use.
The input to your problem is List<Integer>, and so we make a List<List<Integer>> in order to deal with all the input data easily.
Similarly, the output will be arrays, so we make a 2-dimensional array (int[][]) in order to write the data easily.
Then it's simply a matter of iterating over the data in 2 nested for loops. Notice that this line reverses the order of i and j in order to splice the data the way you intend.
myBigArray[i][j] = arraylistList.get(j).get(i);
And then you can print your answer like this:
System.out.println(Arrays.toString(myArray0));
System.out.println(Arrays.toString(myArray1));
System.out.println(Arrays.toString(myArray2));
You need to have two additional structures:
int[][] destination = new int [][] {myArray1, myArray2,myArray3 }
List<Integer>[] source;
source = new List<Integer>[] {arraylist1,arraylist2,arraylist3}
myArray1[1] = arraylist1.get(1);
myArray1[2] = arraylist2.get(1);
myArray1[3] = arraylist3.get(1);
for (int i=0;i<destination.length;i++) {
for (int j=0;j<source.length;j++) {
destination[i][j] = source[j].get(i);
}
}
If you cannot find a ready made API or function for this, I would suggest trivializing the conversion from List to Array using the List.toArray() method and focus on converting/transforming the given set of lists to a another bunch of lists which contain the desired output. Following is a code sample which I would think achieves this. It does assume the input lists are NOT of fixed/same sizes. Assuming this would only make the logic easier.
On return of this function, all you need to do is to iterate over the TreeMap and convert the values to arrays using List.toArray().
public static TreeMap<Integer, List<Integer>> transorm(
List<Integer>... lists) {
// Return a blank TreeMap if not input. TreeMap explanation below.
if (lists == null || lists.length == 0)
return new TreeMap<>();
// Get Iterators for the input lists
List<Iterator<Integer>> iterators = new ArrayList<>();
for (List<Integer> list : lists) {
iterators.add(list.iterator());
}
// Initialize Return. We return a TreeMap, where the key indicates which
// position's integer values are present in the list which is the value
// of this key. Converting the lists to arrays is trivial using the
// List.toArray() method.
TreeMap<Integer, List<Integer>> transformedLists = new TreeMap<>();
// Variable maintaining the position for which values are being
// collected. See below.
int currPosition = 0;
// Variable which keeps track of the index of the iterator currently
// driving the iteration and the driving iterator.
int driverItrIndex = 0;
Iterator<Integer> driverItr = lists[driverItrIndex].iterator();
// Actual code that does the transformation.
while (driverItrIndex < iterators.size()) {
// Move to next driving iterator
if (!driverItr.hasNext()) {
driverItrIndex++;
driverItr = iterators.get(driverItrIndex);
continue;
}
// Construct Transformed List
ArrayList<Integer> transformedList = new ArrayList<>();
for (Iterator<Integer> iterator : iterators) {
if (iterator.hasNext()) {
transformedList.add(iterator.next());
}
}
// Add to return
transformedLists.put(currPosition, transformedList);
}
// Return Value
return transformedLists;
}

Categories