Reputation: 23
I've got the following Java code but List.indexOf() seems to do pretty much the same thing (including returning -1 if not found. Is there any way of passing indexOf() an Object that expresses the idea that the object is not 0?
/**
* Find the first non-zero element in a List of Integers
* @param row List of Integers
* @return -1 if all zeros in row
* otherwise position of first non zero element
*/
public static int leading(List<Integer> row) {
for (int i = 0; i < row.size(); i++) {
if (row.get(i)!= 0) {
return i;
}
}
return -1;
}
Re: Thorbjørn Ravn Andersen: If I passed in null into IndexOf() it will always return -1 because my list always contains Integers. I want to do something like row.indexOf(Integer a where !a.equals(0)). Not sure if possible
Upvotes: 2
Views: 2787
Reputation: 383756
List.indexOf
"solution"List.indexOf(Object o)
is defined as follows:
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 indexi
such that(o==null ? get(i)==null : o.equals(get(i)))
is
true
, or-1
if there is no such index.
It is tempting to try to give a "meta" element object that is not really in the List
, and may not even be of the same type as the actual elements of the List
, and yet is equals
to some desired element based on a predicate. This should work, since indexOf
is defined in terms of the given Object o
's equals
method against an element in the list (and not the other way around), but is a really "hacky" way of achieving what you want.
Here's a proof of concept:
// PROOF OF CONCEPT ONLY! DO NOT IMITATE!
// abusing indexOf(Object) to find index of a negative integer in List
List<Integer> nums = Arrays.asList(3,4,5,-6,7);
Object equalsNegativeInteger = new Object() {
@Override public boolean equals(Object o) {
return (o instanceof Integer) && ((Integer) o) < 0;
}
};
System.out.println(nums.indexOf(equalsNegativeInteger));
// prints 3
The "meta" element object is equals
to any negative Integer
, and yet no Integer
can ever be equals
to it. This asymmetry is a gross violation of the equals
contract, but it "works" nonetheless.
A much better solution that conveys the intent is using Guava's higher-order functions. Here's one from com.google.commons.collect.Iterables
:
<T> int indexOf(Iterable<T> iterable, Predicate<? super T> predicate)
Returns the index in iterable of the first element that satisfies the provided predicate, or
-1
if theIterable
has no such elements. More formally, returns the lowest indexi
such that:predicate.apply(Iterables.get(iterable, i))
is
true
, or-1
if there is no such index.
Here's a snippet to illustrate the expressive power of Guava's higher-order functions:
import com.google.common.collect.*;
import com.google.common.base.*;
import java.util.*;
public class IterablesPredicateExample {
public static void main(String[] args) {
List<Integer> nums = Arrays.asList(1,2,-3,4,-5,6,-7,-8);
Predicate<Integer> isNegative = new Predicate<Integer>() {
@Override public boolean apply(Integer n) {
return n < 0;
}
};
// Get index of first negative number
System.out.println(Iterables.indexOf(nums, isNegative));
// 2
// Find that number
System.out.println(Iterables.find(nums, isNegative));
// -3
// Find all negative numbers
System.out.println(Iterables.filter(nums, isNegative));
// [-3, -5, -7, -8]
// Are all numbers negative?
System.out.println(Iterables.all(nums, isNegative));
// false
// Find all non-negative numbers
System.out.println(Iterables.filter(nums, Predicates.not(isNegative)));
// [1, 2, 4, 6]
}
}
List.indexOf(Object)
can be abused to find elements that satisfy a given predicate, but this is a violation the equals
contractPredicate
and higher-order functions like indexOf
, find
, filter
, all
, any
etc allows you to express these operations in a much more powerfully expressive waysUpvotes: 6
Reputation: 70564
No, java doesn't support closures.
The standard workaround is using an anonymous inner class, but that requires enough boilerplate code to render the solution just a complex as implementing that loop.
Upvotes: 0
Reputation: 160974
The List.indexOf(Object)
method will return the first index at which the specified Object
is found.
The code that is given in the question appears to have the following requirements:
0
is not found in the list.-1
.Unfortunately, there is no way to express the above using the indexOf
method.
Therefore, the code you've presented seems to be an acceptable implementation for the requirements.
Upvotes: 1
Reputation: 75376
I do not believe such a method exists in the standard runtime library.
Question is whether you need this so much that it pays off to keep track of the not-zero values, or you can do with a brute force search. I would do with the latter, and keep track of the difference between System.currentMillis() and if it goes over a limit decided by you, log it. Then you don't have to run a profiler to locate a known possible bottleneck.
Also note you do autoboxing in your sample. That overhead may be unneccesary.
Upvotes: -1