I have two char arrays generated from two strings.I would like to determine whether the arrays are equals.
str1Array = str1.toCharArray();
str2Array = str2.toCharArray();
My understanding is that str1Array.equals(str2Array) will only return true when the array objects are the same object in memory. If I want to check whether each of the indices are the same, I should use Arrays.equals(str1Array, str2Array)
I am wondering about the complexity of this equals method.
I assume it cannot be O(1) because it is not able to evaluate the content equality of the array objects without checking equality for each index. My guess is that it is O(n) where n corresponds to the min(str1Array.length, str2Array.length)
Can anyone verify this or comment otherwise?
Well, let's look at the source code:
public static boolean equals(Object[] a, Object[] a2) {
if (a==a2)
return true;
if (a==null || a2==null)
return false;
int length = a.length;
if (a2.length != length)
return false;
for (int i=0; i<length; i++) {
Object o1 = a[i];
Object o2 = a2[i];
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return true;
}
(It's about the same for the other variations of the method).
As we can see, it's iterating through the array. So it has a worst-case complexity of O(n), where n is the length of the arrays compared. (If the arrays are different sizes, then it exits immediately, making it O(1)).
However, it doesn't always take that long. It does have some preconditions for equality, a null check, and a length check. It also exits as soon as a match is found, so it could take a lot less time.
Related
The following is the source code for Conlletion.contains(Object o) in ArrayList:
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/**
* Returns the index of the first occurrence of the specified element
* in this list, or -1 if this list does not contain the element.
* More formally, returns the lowest index <tt>i</tt> such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
* or -1 if there is no such index.
*/
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
I want to know why not type check first,for example:
public boolean contains(Object o) {
if(o.getClass() != elementData[0].getClass())
return false;
return indexOf(o) >= 0;
}
This is more efficient when o is a different type,isn't it?
(ps:Sorry, my English is not very good, I don't know if I speak clearly)
Since elementData is always allocated as an Object[], the expression elementData.getClass().getComponentType() is the same as Object.class, so if (o.getClass() != elementData.getClass().getComponentType()) would pretty such always be true, i.e. contains() would pretty such always return false.
Your suggestion wouldn't work, that's why it's not done that way.
Besides, even if you could, it still wouldn't work, because the values of a Collection object can be any subclass of the type specified for the collection.
E.g. an ArrayList<Number> can contain a mix of Integer, Long, Double, ... objects, so even if elementData.getClass().getComponentType() would have returned Number.class, it would still be a bad type check.
I am only guessing but I think it was an api design decision.
Since Java supports overwriting the equals method- it is up to the programmer to decide what it means for two objects to be equal. In theory, two objects of different types can be considered equal in a certain domain. It is true that checking for type equality is common when implementing equals, but it is not a mandatory. Since contains is a method for the most general case, no assumptions were made regarding the domain it would be called in.
This question already has answers here:
Comparing integer Arrays in Java. Why does not == work?
(3 answers)
Closed 6 years ago.
When I am trying to compare two int array, even though they are exactly the same, the code inside if (one == two) still doesn't get executed. Why is this?
Object[] one = {1,2,3,4,5,6,7,8,9};
Object[] two = {1,2,3,4,5,6,7,8,9};
if (one == two){
System.out.println("equal");
} else {
System.out.println("not equal");
}
A few things to note here:
== compares the references, not the values . . . that is, you are asking whether these two arrays are the same exact instance, not whether they contain the same values.
The fact that you are using == means you may not know about the equals() method on Object. This is not the method you'll need to solve this current problem, but just be aware that in general, when you compare the values of two objects, you should be using obj1.equals(obj2), not obj1 == obj2. Now == does work with primitives like int (e.g. plain old x == 3 and so on), so maybe that's why you were using it, but I just wanted to make sure you were aware of equals() vs. ==.
In the old old days (pre-1998), you would have to compare each element pair of the two arrays. Nowadays, you can just use that static Arrays.equals() method on the java.util.Arrays class. This method is overloaded for all the primitive types (using == under the hood for each element pair) and for Object (where it will most definitely use equals() for each pair.)
The == operator does a reference equality check on objects (which arrays are). If the array elements are primitive (like int), you can use java.util.Arrays.equals. If they are themselves Objects, java.util.Arrays.deepEquals will do a deep equality test (provided the Objects in the array supply a suitable override of Object#equals.
You can do something like that:
public boolean compareArrays(int[] a, int[] b) {
boolean check = true;
if (a!= null && b!= null){
if (a.length != b.length){
check= false;
}else
for (int i = 0; i < b.length; i++) {
if (b[i] != a[i]) {
check= false;
}
}
}else{
check= false;
}
return check;
}
Or you could do something like that:
boolean areEqual = Arrays.equals(Arrays.sort(arr1), Arrays.sort(arr2));
You are comparing references. Compare the content instead with: Arrays.equals(one, two)
If you do this:
if (one == two){
then yo are comparing the references of the 2 arrays and not their content and that is wrong..
do instead
Arrays.equals(one, two)
== operator compares references and not actual values of everything that extends Object in java. This approach works on primitives only.
In python, you can do
if(a!=b!=c)
How can you do the same thing in Java without having to separate them and write all the "&&" operators? I'm trying to check that all 10 elements are not equal, and I don't want to have to write the equality statement 45 times.
You cannot do that operation in Java. Note furthermore that if a, b, etc., are not primitives, then you should probably be using equals instead of == (or !=). The latter only check for object identity, not equality of values.
If you want to check whether 10 elements are all distinct, you can throw them into a Set implementation (such as HashSet) and check that the set contains 10 elements. Or better (thanks to #allonhadaya for the comment), check that each element was added. Here's a generic method that works for an arbitrary number of objects of arbitrary type:
public static <T> boolean areDistinct(T... elements) {
Set<T> set = new HashSet<T>();
for (T element : elements) {
if (!set.add(element)) {
return false;
}
}
return true;
}
If your elements are primitives (e.g., int), then you can write a non-generic version for the specific type.
Something wrong in your program, if you need to compare 45 variables.
Try to use arrays and cycles.
There's no such option in java (you cannot do such thing without using &&). Java is not Python
Honestly, no, there's no native way to do this in Java.
But, why don't we implement the syntactic sugar for Python's all method instead? With varargs, it's not difficult. It does have an O(n) runtime cost, though.
public static boolean all(Boolean... theBools) {
Boolean result = Boolean.TRUE;
for(Boolean b : theBools) {
if(null == b || !b) {
result = Boolean.FALSE;
break;
}
}
return result;
}
You can use it then like this:
if(YourClass.all(a, b, c, d, e, f, g, h, i, j)) {
// something to do if ALL of them are true
}
I agree that Set is probably the most efficient solution, but if you need to supply some kind of customization to the comparison, you could use something like...
Comparable[] values = new Comparable[]{1, 2, 3, 4, 5};
boolean matches = true;
for (int outter = 0; outter < values.length; outter++) {
for (int inner = outter + 1; inner < values.length; inner++) {
matches &= values[outter].compareTo(values[inner]) == 0;
}
}
System.out.println(matches);
I must be missing something very obvious, but I've searched all over and can't find this method.
There are a couple of ways to accomplish this using the Arrays utility class.
If the array is not sorted and is not an array of primitives:
java.util.Arrays.asList(theArray).indexOf(o)
If the array is primitives and not sorted, one should use a solution offered by one of the other answers such as Kerem Baydoğan's, Andrew McKinlay's or Mishax's. The above code will compile even if theArray is primitive (possibly emitting a warning) but you'll get totally incorrect results nonetheless.
If the array is sorted, you can make use of a binary search for performance:
java.util.Arrays.binarySearch(theArray, o)
Array has no indexOf() method.
Maybe this Apache Commons Lang ArrayUtils method is what you are looking for
import org.apache.commons.lang3.ArrayUtils;
String[] colours = { "Red", "Orange", "Yellow", "Green" };
int indexOfYellow = ArrayUtils.indexOf(colours, "Yellow");
For primitives, if you want to avoid boxing, Guava has helpers for primitive arrays e.g. Ints.indexOf(int[] array, int target)
There is none. Either use a java.util.List*, or you can write your own indexOf():
public static <T> int indexOf(T needle, T[] haystack)
{
for (int i=0; i<haystack.length; i++)
{
if (haystack[i] != null && haystack[i].equals(needle)
|| needle == null && haystack[i] == null) return i;
}
return -1;
}
*you can make one from your array using Arrays#asList()
Unlike in C# where you have the Array.IndexOf method, and JavaScript where you have the indexOf method, Java's API (the Array and Arrays classes in particular) have no such method.
This method indexOf (together with its complement lastIndexOf) is defined in the java.util.List interface. Note that indexOf and lastIndexOf are not overloaded and only take an Object as a parameter.
If your array is sorted, you are in luck because the Arrays class defines a series of overloads of the binarySearch method that will find the index of the element you are looking for with best possible performance (O(log n) instead of O(n), the latter being what you can expect from a sequential search done by indexOf). There are four considerations:
The array must be sorted either in natural order or in the order of a Comparator that you provide as an argument, or at the very least all elements that are "less than" the key must come before that element in the array and all elements that are "greater than" the key must come after that element in the array;
The test you normally do with indexOf to determine if a key is in the array (verify if the return value is not -1) does not hold with binarySearch. You need to verify that the return value is not less than zero since the value returned will indicate the key is not present but the index at which it would be expected if it did exist;
If your array contains multiple elements that are equal to the key, what you get from binarySearch is undefined; this is different from indexOf that will return the first occurrence and lastIndexOf that will return the last occurrence.
An array of booleans might appear to be sorted if it first contains all falses and then all trues, but this doesn't count. There is no override of the binarySearch method that accepts an array of booleans and you'll have to do something clever there if you want O(log n) performance when detecting where the first true appears in an array, for instance using an array of Booleans and the constants Boolean.FALSE and Boolean.TRUE.
If your array is not sorted and not primitive type, you can use List's indexOf and lastIndexOf methods by invoking the asList method of java.util.Arrays. This method will return an AbstractList interface wrapper around your array. It involves minimal overhead since it does not create a copy of the array. As mentioned, this method is not overloaded so this will only work on arrays of reference types.
If your array is not sorted and the type of the array is primitive, you are out of luck with the Java API. Write your own for loop, or your own static utility method, which will certainly have performance advantages over the asList approach that involves some overhead of an object instantiation. In case you're concerned that writing a brute force for loop that iterates over all of the elements of the array is not an elegant solution, accept that that is exactly what the Java API is doing when you call indexOf. You can make something like this:
public static int indexOfIntArray(int[] array, int key) {
int returnvalue = -1;
for (int i = 0; i < array.length; ++i) {
if (key == array[i]) {
returnvalue = i;
break;
}
}
return returnvalue;
}
If you want to avoid writing your own method here, consider using one from a development framework like Guava. There you can find an implementation of indexOf and lastIndexOf.
Java ArrayList has an indexOf method. Java arrays have no such method.
I don't recall of a "indexOf" on arrays other than coding it for yourself... though you could probably use one of the many java.util.Arrays#binarySearch(...) methods (see the Arrays javadoc) if your array contains primitive types
The List interface has an indexOf() method, and you can obtain a List from your array with Array's asList() method. Other than that, Array itself has no such method. It does have a binarySearch() method for sorted arrays.
Arrays themselves do not have that method. A List, however, does:
indexOf
You're probably thinking of the java.util.ArrayList, not the array.
There is no direct indexOf function in java arrays.
Jeffrey Hantin's answer is good but it has some constraints, if its this do this or else to that...
You can write your own extension method and it always works the way you want.
Lists.indexOf(array, x -> item == x); // compare in the way you want
And here is your extension
public final class Lists {
private Lists() {
}
public static <T> int indexOf(T[] array, Predicate<T> predicate) {
for (int i = 0; i < array.length; i++) {
if (predicate.test(array[i])) return i;
}
return -1;
}
public static <T> int indexOf(List<T> list, Predicate<T> predicate) {
for (int i = 0; i < list.size(); i++) {
if (predicate.test(list.get(i))) return i;
}
return -1;
}
public interface Predicate<T> {
boolean test(T t);
}
}
int findIndex(int myElement, int[] someArray){
int index = 0;
for(int n: someArray){
if(myElement == n) return index;
else index++;
}
}
Note: you can use this method for arrays of type int, you can also use this algorithm for other types with minor changes
What's the most compact code to compare three objects for (semantic) equality using Java? I have a business rule that the objects must be unique i.e. A is different to B, A is different to C and B is different to C.
Assume that the objects are all of the same class and have correctly overridden equals and hashCode methods. A slight wrinkle is that object C could be null—if this is the case then A and B have to be different to each other.
I have some code but it's a bit workmanlike for my tastes.
As the OP said A and B are never null, C may be null, use this:
if(A.equals(B) || B.equals(C) || A.equals(C))
// not unique
and, as others have already suggested, you can put it in a method for reuse. Or a generic method if you need more reuse ;-)
Note that in Java, a feature of equals is that if its argument is null it should not throw, but return false.
Since I never start a Java project without using Apache commons-lang, try ObjectUtils.equals (it's null safe):
if (ObjectUtils.equals(a, b) || ObjectUtils.equals(b, c) || ObjectUtils.equals(a, c)) {
// error condition
}
Put that logic in a generic method, and you'll do even better.
While the business logic allows C to be null, in scenarios like this, it's often better to code defensively and assume that either A or B could be null as well.
You can abstract that method in a utilities method like:
public boolean allUnique(Object... objs) {
Set<Object> set = new HashSet<Object>();
for (Object o : objs)
set.add(o);
return set.size() == objs.length
}
The method may not perform well for small numbers (due to the overhead of creating the Set and the varargs array). However, it grows linearly O(n), and for large values it's better than the quadratic growth of a nested if statements.
boolean areDistinct(Object a, Object b, Object c) {
return (!a.equals(b) &&
(c == null || (!c.equals(a) && !c.equals(b))));
}
As the apache's common.lang3.ObjectUtils.equals() is #Deprecated. Use Objects.equals(aObj,bObj). Comparison should be made with && if you want that all 3 objects are the same. Use || if you want that just one combination of a&b, a&c or b&c is the same.
/**
* Compare 3 objects of the same {#link TYPE}, if they are all equal using {#link Objects#equals(Object, Object)}.
*
* #param aObj the 1st object
* #param bObj the 2nd object
* #param cObj the 3th object
* #param <TYPE> the type of the objects
* #return true if the are all the same
*/
public static <TYPE> boolean equals(TYPE aObj, TYPE bObj, TYPE cObj) {
return Objects.equals(aObj, bObj) && Objects.equals(bObj, cObj) && Objects.equals(cObj, aObj);
}
As long as your objects implement equals, you can use the Stream API to get a distinct set of values, and if that distinct count is 1, they are all the same.
boolean allEqual = Stream.of(obj1, obj2, obj3).distinct().count() == 1
package com.test;
public class Equality {
public static void main(String[] args) {
Boolean flag;
int[] arr={1,1,1,12};
flag=check_equal(arr);
System.out.println(flag);
}
public static Boolean check_equal(int[] arr){
Boolean flag=true;
outerloop:
for(int i=1; i< arr.length; i++)
{
for(int j=1; j< arr.length; j++){
if(arr[i]==arr[j]){
flag=true;
}
else{
flag=false;
break outerloop;
}
}
}
return flag;
}
}