Where is Java's Array indexOf?
Asked Answered
A

13

247

I must be missing something very obvious, but I've searched all over and can't find this method.

Auroraauroral answered 10/2, 2011 at 20:36 Comment(0)
N
272

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)
Norean answered 10/2, 2011 at 20:40 Comment(13)
I'm pretty sure this answer is wrong at least for java 1.6: download.oracle.com/javase/6/docs/api/java/util/… asList transforms the list of arguments into a list not the argument itself.Arella
@Arella Ellipsis handling is syntactic sugar. If you have an argument typed T..., the actual run-time type of the argument is T[], and passing zero or more parameters of type T results in them being wrapped into a newly constructed array and passed. If the parameter being passed is already of type T[], the syntactic sugar is bypassed.Norean
I see your point. The solution (.indexOf) is not valid for primitives, though.Arella
@Arella Wouldn't primitives end up boxed, since T becomes Object under type erasure?Norean
@Jeffrey: boxing does not work for arrays, only for single values. (Also, you normally would not want to convert a whole array "on the fly". Better have some list wrapper around your primitive array.)Aliquot
@Paŭlo: I think we're talking about orthogonal cases here. Primitives typed directly inline using the ellipsis sugar (e.g. Arrays.asList(1, 2, 3)) should be individually boxed as the resulting Object[] argument is constructed. Passing an existing primitive array wouldn't work since int[] isn't a subtype of Object[].Norean
@Jeffrey: Ah. I neglected to read your first comment, and only related the second comment to the answer (and question). Sorry.Aliquot
Since nobody mentioned: Arrays.asList uses the already-existing array as the backing. (I.e. there's no concern about a copy being created.)Crass
This solution is still not good if you want to search from a given offset. For example String's interface knows that. It would be essential (IMO) for simple arrays to know that.Neeley
@Neeley The java guys thought of that too. Use Arrays.toList(list).sublist(from,to).indexOf(o) to search for an element within the range [from, to).Latham
Arrays.binarySearch will not work deterministically on some cases because "If the array contains multiple elements with the specified value, there is no guarantee which one will be found."Interviewee
@DenRoman, binarySearch is quite deterministic: for the same input array and search key, it will consistently return the same index. The 'no guarantee' language relates to the search terminating at the first match it stumbles upon.Norean
Specify a primitive array in Arrays.asList(theArray) at your own peril! If you're lucky (Eclipse 4.7+?), you'll get an unlikely-arg-type warning. If not, you'll get compiling code that's syntactically incorrect.Hirundine
M
80

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");
Mischievous answered 10/2, 2011 at 20:41 Comment(0)
P
22

For primitives, if you want to avoid boxing, Guava has helpers for primitive arrays e.g. Ints.indexOf(int[] array, int target)

Pulsimeter answered 16/8, 2011 at 19:26 Comment(1)
The other solutions all create new strings or lists or just handle single elements. Guava's Chars.indexOf lets you get the index of an array in an array. This is the correct solution.Mendelssohn
A
21

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:

  1. 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;

  2. 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;

  3. 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.

  4. 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.

Abrasive answered 29/9, 2013 at 23:12 Comment(0)
D
20

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()

Deration answered 10/2, 2011 at 20:41 Comment(6)
Using T is misleading. It does not provide any type safety, easy to mistake it is type safe... better use ObjectBoogiewoogie
@VenkataRaju, using T here forces both method parameters to be of the same type. That's useful.Gunzburg
@Gunzburg Not really. Both of these compiles just fine: indexOf("str", new Object[] {});, indexOf(new Object(), new String[] {});Boogiewoogie
@VenkataRaju Yes really. Your example doesn't prove anything since a String is an Object... so obviously an Object array could contain a String that you might want to find the index of.Mesmerize
@ghert85 Another example: indexOf("str", new Date[] {}), indexOf(new Date(), new String[] {})Boogiewoogie
It doesn't work with primitives.Privity
S
14

Java ArrayList has an indexOf method. Java arrays have no such method.

Subphylum answered 10/2, 2011 at 20:39 Comment(1)
Not just ArrayList - every Java List has indexOf().Deration
B
7

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

Bourgogne answered 10/2, 2011 at 20:40 Comment(0)
N
5

Arrays themselves do not have that method. A List, however, does: indexOf

Nectarous answered 10/2, 2011 at 20:40 Comment(2)
Not just ArrayList - every Java List has indexOf().Deration
Yeah, I just specified ArrayList because that may be the closest thing to what the OP was looking for :)Nectarous
M
5

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.

Mellie answered 10/2, 2011 at 20:40 Comment(0)
L
3

You're probably thinking of the java.util.ArrayList, not the array.

Libertinism answered 10/2, 2011 at 20:39 Comment(0)
I
3

There is no direct indexOf function in java arrays.

Inviolable answered 19/10, 2016 at 2:51 Comment(0)
P
1

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);
    }
}
Personnel answered 2/12, 2018 at 9:12 Comment(0)
A
-5
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

Alagoas answered 14/10, 2017 at 11:19 Comment(2)
-1: First this mutates the original array to be sorted which we may not want. Second it gives the answer wrt the sorted array, not the original array which is likely what we want (if we wanted the answer wrt sorted array, it would already be sorted). Third since sorting is O(n log n) this is slower than just going through the array linearly. So this answer is both wrong and inefficient.Auroraauroral
the original index was lost when an in-place sort is used.Tristis

© 2022 - 2024 — McMap. All rights reserved.