Java indexOf方法作为手动搜索的捷径

时间:2010-08-07 11:03:55

标签: java

我有以下Java代码,但List.indexOf()似乎做了几乎相同的事情(包括如果没有找到则返回-1。有没有办法传递indexOf()一个表达这个想法的对象对象不是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ørnRavnAndersen:如果我将null传入IndexOf(),它将始终返回-1,因为我的列表总是包含整数。我想做一些像row.indexOf(Integer a where!a.equals(0))的东西。不确定是否可能

4 个答案:

答案 0 :(得分:6)

List.indexOf“解决方案”

List.indexOf(Object o)定义如下:

  

返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。更正式地,返回最低索引i,使

(o==null ? get(i)==null : o.equals(get(i)))
     

true,如果没有这样的索引,则为-1

尝试提供一个实际上不在List中的“meta”元素对象很有诱惑力,甚至可能与List的实际元素的类型不同,并且然而equals是基于谓词的某个所需元素。这应该有效,因为indexOf是根据给定Object o的{​​{1}}方法针对列表中的元素定义的(而不是相反),但实际上是“ hacky“实现你想要的方式。

以下是概念证明:

equals

“meta”元素对象// 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 对任何否定equals,但IntegerInteger不能equals。这种不对称严重违反了the equals contract,但它“仍然有效”。


番石榴溶液

传达意图的更好的解决方案是使用Guava的高阶函数。这是com.google.commons.collect.Iterables中的一个:

  

<T> int indexOf(Iterable<T> iterable, Predicate<? super T> predicate)

     

返回满足所提供谓词的第一个元素的iterable中的索引,如果-1没有这样的元素,则返回Iterable。更正式地,返回最低索引i,使得:

 predicate.apply(Iterables.get(iterable, i))
     

true,如果没有这样的索引,则为-1

这里有一个片段来说明番石榴高阶函数的表达能力:

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)来查找满足给定谓词的元素,但这违反了equals合同
  • 使用Guava的Predicate及更高阶函数,例如indexOffindfilterallany等,可让您表达这些操作以更有力的表达方式

答案 1 :(得分:1)

List.indexOf(Object)方法将返回找到指定Object的第一个索引。

问题中给出的代码似乎具有以下要求:

  • 返回列表中找到0 的第一个索引。
  • 如果列表中不存在此类元素,请返回-1

不幸的是,无法使用indexOf方法表达上述内容。

因此,您提供的代码似乎是可接受的要求实现。

答案 2 :(得分:0)

不,java不支持闭包。

标准的解决方法是使用匿名内部类,但这需要足够的样板代码来使解决方案变得复杂,因为实现了该循环。

答案 3 :(得分:-1)

我不相信标准运行时库中存在这样的方法。

问题是你是否需要这么多,以便记录非零值,或者你可以用暴力搜索。我会使用后者,并跟踪System.currentMillis()之间的区别,如果它超过了您决定的限制,请记录它。然后,您不必运行探查器来查找已知的可能瓶颈。

另请注意,您在样本中进行自动装箱。这种开销可能是不必要的。