Linear scan for comparing two arrays in Java - java

I am currently attempting to write an algorithm that can scan two arrays for equality in O(N) time, using Java. The idea is that the arrays should be exactly equal, regardless of order, for the method to return true. What was recommended to me was to use linear scan, but use one loop to scan and compare two arrays. This is what I have:
public boolean equals(ArraySet<T> s) {
T[] sArray = s.getArray();
boolean isEqual = true;
if (!(s.size() == size())) {
return false;
}
int i = 0;
int p = 0;
while ((i < elements.length) && (p < sArray.length)) {
if (elements[i].compareTo(sArray[p]) != 0) {
isEqual = false;
p++;
continue;
}
i++;
p = 0;
isEqual = true;
}
return isEqual;
I'm confident that this algorithm will return the equality correctly, but I'm not so sure that it will do so in O(N) time complexity. Is there anything I could tweak to ensure that this method functions with the proper efficiency? ArraySet is a Set implementation that contains an array field, returned by getArray(). This array and the local array can be assumed to already be in ascending natural order, however the parameter array and the local array can obviously not be assumed to have the same elements.

First of all, what you are doing in your while loop isn't correct.
Scenario 1: Even if we assume both array's are sorted, in your while loop you are incrementing only p and not i. That is if you have two arrays: element={1,2,3} sArray={1,2,3}; you are just comparing element[0] with rest of sArray.
Scenario 2:Let's say both arrays equal in length but are not in sorted order.
element={1,2,3} sArray={2,1,3}; Even here your code again just compares element[0] with rest of the sArray.
A better approach is to use a HashSet and compare your element array to hashset.
Here is a simple example to compare arrays:[we are assuming there are not duplicates in the both arrays, else this solution wont work]
Set<Integer> uniqueList = new HashSet<Integer>();
int[] elements={1,2,3};
int[] sArray = {3,2,1};
boolean isArrayElementsEqual = false;
for(int i=0;i<sArray.length;i++){
uniqueList.add(sArray[i]);// add one of the arrays complete elements into a set
}
for(int i=0;i<elements.length;i++){
if(uniqueList.contains(elements[i])){//compare another array elements with the set, if its exists them remove it from set..such that by the end of this if both arrays have equal contents, set should be empty
uniqueList.remove(elements[i]);
}
}
if(uniqueList.isEmpty()){//if this list is empty it means both arrays have same contents
isArrayElementsEqual = true;
return isArrayElementsEqual;
}
return isArrayElementsEqual;
P.S: You could modify it based on your requirement

Related

Array contains element in Java

I've got a task of writing a function that returns integers which are in both two arrays.
For example: nums1 [1,2,3] and nums2 [2,3,5] and answer should be [2,3].
I came with this solution:
public static void main(String[] args) {
System.out.println(arraysIntersection(new int[] {1,2,3}, new int[] {2,3,5}));
}
public static List<Integer> arraysIntersection(int[] nums1, int[] nums2) {
List<Integer> answer = new ArrayList<>();
for (int i = 0; i < nums1.length; i++) {
if (Arrays.asList(nums2).contains(nums1[i])) {
answer.add(nums1[i]);
}
}
return answer;
}
however it seems this condition doesn't work as intended:
if (Arrays.asList(nums2).contains(nums1[i]))
It says it doesn't contain the value altough it clearly contains 2 and 3. Any ideas?
I know I could just iterate each i over the second array but I thought this solution would be faster. Does anyone knows why it's not working?
You can do it in O(NlogN) time complexity and O(n) memory. Just sort arrays and use two pointers technique.
List<Integer> answer = new ArrayList<>();
int j = 0;
Arrays.sort(nums1);
Arrays.sort(nums2);
for(int i = 0; i < nums1.length; i++) {
if(i > 0 && nums1[i] == nums1[i - 1]) //we have already processed this number
continue;
while(j < nums2.length && nums2[j] < nums1[i])
j++;
if(j < nums2.length && nums1[i] == nums2[j])
answer.add(nums1[i]);
}
return answer;
You can do it in O(N) time complexity and O(n) memory (but constant is higher). Just add all elements of nums1 in first HashSet and all elements of nums2 if another HashSet. Then you can for each element in first set check if another set contains this element using O(1)* time.
List<Integer> answer = new ArrayList<>();
Set<Integer> set1 = new HashSet<>(), set2 = new HashSet<>();
set1.addAll(nums1);
set2.addAll(nums2);
for(var el : set1) {
if(set2.contains(el)) {
answer.add(el);
}
}
return answer;
*O(1) is middle time of operations with hashset
If Arrays is a static object already initialized, or declared at global scope, it may be OK, I don't know for sure. Can't call asList() on an uninitialized object, it must be allocated first.
Now I know, Arrays is a member of the utils package, can be OK.
But not anything that looks fine in code, actually works also.
As a matter of fact, I don't like the way in which Java calls a function. But it would be more easier and handy like this.
I don't know, if you had included the util package in your code.
util, or utils ? Can be 2 different packages, this is important.
You can try another way:
import java.util.*;
public static List<Integer> arraysIntersection(int[] nums1, int[] nums2){
List<Integer> answer = new ArrayList<>();
for (int i = 0; i < nums1.length; i++) {
int u = nums1[i];
for (int j = 0; j < nums2.length; j++) {
if (u == nums2[j]) {
answer.add(u);
break;
}
}
}
return answer;
}
A break could be necessary, if the values must be added only once.
( a number can be found more times into an array )
The break was meant just for ending the inner loop.
The outer loop should continue up to the end of the search.
But the same number can be find more times in the first array.
Before returning the answer, the result should be checked for duplicate values. And this is another problem.
It would be more convenient to check before adding number to list.
Check if the answer list already contains the number value.
And then add the number to the list, if a match is not found.
So this can be done more easier:
if (!answer.contains(u)) answer.add(u);
Since you check this condition, the break is not anymore needed.
But searching the list so many times, can slow down your code.
From this reason, the u value is read only once, before starting to compare with the another array. So you don't have to read manytimes the same array item, just store it in a temporary variable, u.
In another point of view, when iterating over a collection object,
the current value for the current position index could change.
It also depends on the basic interface implementation for this object.
If this function would have been written in C, it would have been a very serious problem, to get the value of an item in array, because the current position of the pointer changes. And here is the same, the current read value changes, excepting that we can't see all the underlying mechanism. And if I am not wrong too much, the original Java first time was based also on the C code.
Best regards, Adrian Brinas.
Have a nice day.

In java,how to check elements in a 1-D array are different to each other?

For example,I have an 1-D array ,how can I check if all the elements are different?(no one same with other,all of them should be different) Use for-loop?Or something else?
I thought maybe this,but cannot be true:
int []array={1,2,3,4,4,6}
for(int i=0;i<a.length;i++){
if(a[i]!=a[i+1])
return true;
else
return false;
}
so is there some good method can use to check different?
Add all items from the array into a Set and check the set size with the original array size.
If they're different sizes, then there's a duplicate element.
Create a HashSet (or another kind of Set), and loop through the elements of your array. Add them one at a time. If the element already exists in the Set, then not all are different and you can return false. You can tell this if add returns false; then you don't have to check the rest of the array. If you finish with the entire array and none are the same, then they're all different and you can return true.
The problem with your current code is that you only check the first and second elements, and you return something right away based on that comparison, and you don't consider the rest of the elements.
There are several ways to do this. For example, you can use two for loops:
boolean hasDuplicates(int[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length; j++) {
if (array[i] == array[j]) {
return true;
}
}
}
return false;
}
If that’s too much writing for you, you can just create a Set from the array and compare the size of the set and the array. The set automatically drops duplicate entries.
Set<String> values = new HashSet<>(Arrays.asList(array));
assertEquals(array.length, values.size());

How to compare arraylist value and array value in java

int sizeOfTheShortestList = webresult.size();
for (int i=0; i<sizeOfTheShortestList; i++) {
if (webresult1.get(i).equals(dbresult[i]) )
{
System.out.println("Equals..: " + webresult1.get(i));
}
}
from above code i find errors please give solution to compare arraylist values and array values
Take arraylist as 'al'.
Take array as 'a'.
now u need to compare 'al' and 'a'.
iterator it = new iterator(al);
int length = a.size();
int count=0;
for(int i=0;i<length; i++)
{
if(it.next()==a[i]);
{
count++;
}
}
if(count == length)
{
System.out.println("Both are equal");
}
else
{
System.out.println("Both are not equal");
}
You could use something like ArrayList#retailAll
Retains only the elements in this list that are contained in the
specified collection. In other words, removes from this list all of
its elements that are not contained in the specified collection.
webresult.retainAll(Arrays.asList(dbresult);
// Now webresult will only contain the values that were in webresult and are in dbresult
Try some thing like this
int sizeOfTheShortestList = Math.min(webresult.size(), webresult1.length);
for (int i=0; i<sizeOfTheShortestList; i++) {
if (webresult.get(i).equals(webresult1[i]) {
System.out.println("Equals..: " + webresult.get(i));
}
}
I hope I understood your question in right way..otherwise please comment
First you need to compare the lengths of both webresult and dbresult, because if they are of different lengths you will get IndexOutOfBounds exception.
Is webresult.get(i) is of the same type as of dbresult[i]?
Implementation of equals, missing from question, should add that too, if not using default.
It depends on what kind of errors you get.
Another solution would be to use the toArray() method on your arraylist and compare 2 arrays. But your code should work if the data structures have the same length, because you are comparing the elements from the array and arraylist, not the collections themselves.
Assuming that your arraylist is shorter than the array (otherwise you'd get an IndexOutOfBounds exception), you should make sure that the types of webresult.get(i) and dbresult[i] are the same. Also, ".equals()" only works for comparing objects (such as Strings), and not for primitives. So if webresult.get(i) and dbresult[i] are ints or chars, ".equals" will not work. You should use "==" instead.
You can use the ArrayList#toArray() to convert your list to an array.
Then you can use Arrays#equals() to compare the two arrays.
The objects that you are comparing will have to override Object#eqauls()

Using contains on an ArrayList with integer arrays

I have an ArrayList<int[]>, and I add an array to it.
ArrayList<int[]> j = new ArrayList<int[]>();
int[] w = {1,2};
j.add(w);
Suppose I want to know if j contains an array that has {1,2} in it without using w, since I will be calling it from another class. So, I create a new array with {1,2} in it...
int[] t = {1,2};
return j.contains(t);
...but this would return false even though w was added to the list, and w contains the exact same array as t.
Is there a way to use contains such that I can just check to see if one of the elements of the ArrayList has the array value {1,2}?
Arrays can only be compared with Arrays.equals().
You probably want an ArrayList of ArrayLists.
ArrayList<ArrayList<Integer>> j = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> w = new ArrayList<Integer>();
w.add(1); w.add(2);
j.add(w);
ArrayList<Integer> t = new ArrayList<Integer>();
t.add(1); t.add(2);
return j.contains(t); // should return true.
The problem here is that arrays don't override Object.equals(Object), So the comparison between two list entries happens with the default equals() implementation
// from Object.class
public boolean equals(Object obj) {
return (this == obj);
}
So you have to iterate over the list and check all entries using Arrays.equals(int[], int[]). Here's a Helper method that does this:
public static boolean isInList(
final List<int[]> list, final int[] candidate){
for(final int[] item : list){
if(Arrays.equals(item, candidate)){
return true;
}
}
return false;
}
Update: Ever since Java 8, this has got a lot simpler:
public static boolean isInList(
final List<int[]> list, final int[] candidate) {
return list.stream().anyMatch(a -> Arrays.equals(a, candidate));
// ^-- or you may want to use .parallelStream() here instead
}
You need to iterate through the list and manually check whether an array matches your criteria.
public static boolean containsSubArray(List<int[]> j, int[] sub) {
for ( int[] arr : j ) {
if (arr contains elements of sub) {
return true;
}
}
return false;
}
If you want an exact match, you can make use of Arrays.equals(). I don't think there's a library function to do a contains all on an array though, so you would have to write that yourself if that's what you wanted.
"contains" contract checks for equality. So in your case what is failing is equality of int[]. Since Array does not override the equals method from Object you will need a workaround to check for containment.
If you need to check for containment within the Array then you are left with no choice but to iterate through the ArrayList and do the comparison yourself.
from java api:
public boolean contains(Object o)
Returns true if this list contains the
specified element. More formally,
returns true if and only if this list
contains at least one element e such
that (o==null ? e==null : o.equals(e)).
since int[] is a primitive, im pretty sure no .equals method exists so its my guess it would always return false.
I would recommend a different way of storing the data? maybe with a key of some sort?
Two java array arrays are equal iff they have the same object reference. Content doesn't matter.
You're looking for a way to check if they have an equal content. This could help:
Arrays.equals(new int[]{1,2}, new int[]{1,2}); // evaluates to true
Arrays.equals(new int[]{1,2}, new int[]{2,1}); // evaluates to false (!)
If order shouldn't affect equality, then you will have to implement a static equals method by yourself.
First they are not the same Object reference, so they are not equal. equals() will return false.
For your condition, you will need to implement a method to compare them yourself.
If you have one array and want to compare that all elements of array are present in list:
Long[] array1 = {1111L, 1112L};
Long[] array2 = {1111L, 1114L};
List<Long> list = new ArrayList<>();
list.add(1111L);
list.add(1112L);
list.add(1113L);
Arrays.asList(array1).stream().allMatch(val -> list.contains(val)); //return true
Arrays.asList(array2).stream().allMatch(val -> list.contains(val)); //return false

compare string array using collection

I have two String arrays a,b.
String a [] = {"one","two","three"};
String b [] = {"one","Two","Three","four"};
I need to check whether both arrays are same or not , with case Insensitive .
I know , the following piece of code is perfect for case sensitive.
List <String> l1 = Arrays.asList(a);
List <String> l2 = Arrays.asList(b);
System.out.println(l2.containsAll(l1));
Is there any other way to compare two string array (case Insensitive ) using collection?
Finally , I used TreeSet with case insensitive comparator.
Example :
String [] oldVal = {"one","two","three","Four"};
String [] newVal = {"one","Two","Three","four"};
Set <String> set1 = new TreeSet <String> (String.CASE_INSENSITIVE_ORDER);
Set <String> set2 = new TreeSet <String> (String.CASE_INSENSITIVE_ORDER);
set1.addAll(Arrays.asList(oldVal));
set2.addAll(Arrays.asList(newVal));
System.out.println("--Using Tree Set --- "+ set1.containsAll(set2)); // Return True
Thanks Guys..
Couldn't you just loop it or use some sort of linq (Sorry just noticed this was java you cant use linq...?)
List<string> matches = new List<string>();
bool isSame=true;
foreach(string s1 in l1)
{
foreach(string s2 in l2)
{
if(s1.ToLower() == s2.ToLower())
matches.Add(s1);
else
{
isSame=false;
break;
}
}
if (isSame)
continue;
else
break;
}
if (isSame)
Console.Writeline("They are the same")
else
Console.Writeline("Not the same");
You may want to check the count as I did not add that to the code, for instance l1.count > l2.count (in this case you know whether or not they are the same by the number of elements in the list). Simple test before even looping:
if (l1.Count != l2.Count) {
//don't even bother looping
//display no matches
}
else {
//place rest of code here since l1.count = l2.count
}
CRAP DIDN'T REALIZE THIS WAS FOR JAVA THOUGHT IT WAS FOR C#. APPLY
SAME LOGIC TO JAVA THOUGH...
You could use a TreeMap with a case-insensitive comparator.
If the arrays don't contain duplicates, one way to do this in O(N) is to use a Set that represents a canonical form of the strings in the array. Something like this:
static Set<String> canonicalSet(String[] arr) {
Set<String> upperSet = new HashSet<String>();
for (String s : arr) {
upperSet.add(s.toUpperCase());
}
return upperSet;
}
static boolean equalsCanonically(String[] arr1, String[] arr2) {
return canonicalSet(arr1).equals(canonicalSet(arr2));
}
This is time-optimal.
You can also do variations on this technique to save more space, e.g. instead of constructing the canonical sets and comparing them, you can construct the canonical set for arr1, and then remove entries from that set according to elements of arr2. It the set is empty afterward, and you can always find what you need to remove, the two arrays are canonically equal.
static boolean equalsCanonically2(String[] arr1, String[] arr2) {
Set<String> canon = canonicalSet(arr1);
for (String s : arr2) {
if (!canon.remove(s.toUpperCase())) return false;
}
return canon.isEmpty();
}
You can also do a simple size-comparison check if you think it's worth it (i.e. if often the two arrays don't even have the same number of elements).
If there are duplicates in the arrays, then the Set method will not work as is. You'd need a multiset, and you can either implement your own, or use Google Collections'.
There are also O(N log N) ways to do this involving sorting the strings. You can sort both arrays and then do a simple linear check. A case-insensitive comparator must be used, and in fact it's already there as String.CASE_INSENSITIVE_ORDER.
static boolean equalsCanonically3(String[] arr1, String[] arr2) {
int N = arr1.length;
if (arr2.length != N) return false;
Arrays.sort(arr1, String.CASE_INSENSITIVE_ORDER);
Arrays.sort(arr2, String.CASE_INSENSITIVE_ORDER);
for (int i = 0; i < N; i++) {
if (String.CASE_INSENSITIVE_ORDER.compare(arr1[i], arr2[i]) != 0) {
return false;
}
}
return true;
}
This last technique works even if the arrays contain duplicates. It does it O(N log N). It sorts the arrays passed as parameters, so if the original state is important, you want to pass their clone() instead.
check it in nested loops if you want custom comparison. or if you have large sets of data it might be cheaper to sort arrays first
Your sample data are sorted. If this is guaranteed to be the case in reality, you should do as Andrey says, and use nested loops on the arrays themselves, breaking if/when you find an inequal pair of entries.
If they're not guaranteed to be sorted, I'd dump each of them into a HashSet, and then you can use java's Set containsAll method.
Edit: As Thomman pointed out, containsAll() ultimately relies on equals(). So in order to get the case-insensitive checking your question requests, you have two choices:
1) Upcase or downcase the strings on insertion into the sets. On consideration, I'm not crazy about this method, since not only will you lose duplicate entries, but you'll also fold entries differentiated by case. And so these lists would look to be equal to each other:
String a [] = {"one","one","one", "Two"};
String b [] = {"One", Two"};
2) The other choice is to put your strings into holder objects which override equals(), doing comparison in a case-insensitive way.
You could first check if their lengths are equal. Then you could put items of a in HashMap and go over b and check if the items are there.
Using one for loop -
String [] oldVal = {"one","two","three","Four"};
String [] newVal = {"one","Two","Three","four"};
if(oldVal.length == newVal.length)
{
//
for(int y =0; y<oldVal.length; y++)
{
oldVal[y] = oldVal[y].toUpperCase();
newVal[y] = newVal[y].toUpperCase();
}
return Arrays.asList(oldVal).containsAll(Arrays.asList(newVal));
}
return false;

Categories