问题 Java中的谓词搜索


不太确定如何说出这个问题。 我想知道是否有一种方法来检查自定义java类的某些部分,看它是否符合某个标准。 比如这个

public Name(String forename, String middlename, String surname)

然后当创建该类的实例数组时,

Name[] applicants = new Name[4];

applicants[0] = new Name("john","bob", "rush");
applicants[1] = new Name("joe","bob", "rushden");
applicants[2] = new Name("jack","bob", "rushden");
applicants[3] = new Name("jake","bob", "rushden");

是否可以搜索类的实例

midddlename.equals("bob") && surname.equals("rush")

我并不是在寻找一个解决方案 if(surname.equals("bob")) then else,等等

但更多内置的java类允许快速搜索数组。 速度非常重要。


8819
2018-02-25 17:27


起源

过早优化? - Samuel Carrijo
除非必须使用,否则不应使用数组,列表是所有情况下99.99999%的更好解决方案。 - feeling unwelcome
为什么它是“Java对象问题”? - fastcodejava


答案:


没有内置的支持,但是 Apache集合 和 Google Collections 两者都提供Predicate对集合的支持。

你可能会发现 这个问题 它的答案很有帮助。与此相同 developer.com 文章。

例如使用Google收藏集:

final Predicate<name> bobRushPredicate = new Predicate<name>() {
   public boolean apply(name n) {
      return "bob".equals(n.getMiddlename()) && "rush".equal(n.getSurname());
   }
}

final List<name> results = Iterables.filter(applicants, bobRushPredicate));

14
2018-02-25 17:32



是否有任何地方可以获得有关使用谷歌收集的谓词的教程或更多示例? - pie154
Java 8增加了内置支持。我添加了一个例子作为答案。 - Andrew


搜索数组和“速度非常重要”并不是真的在一起。除非您的阵列非常小,否则搜索数组将永远不会很快。这相当于数据库中的全表扫描,性能无论你怎么做都会很差。快速查找内容的关键是使用索引结构。如果你绝对需要它,你仍然可以拥有一个数组,但是应该使用另一种数据结构进行搜索。检查基于哈希或树的集合,因为它们以一种使检索速度非常快的方式组织数据。 TreeSet,TreeMap,HashSet,HashMap等。散列密钥上的哈希索引数据,树类似,但也按排序顺序存储它们的数据。


1
2018-02-25 20:58



只是一个小注,但您所指的结构,树和地图,仍然基于数组。他们只是使用特定的方法来搜索数组。 - Matt
有一些方法可以更快地搜索数组,首先 - 将数组排序一次将加速搜索从线性到对数,其次 - 它是“令人难以置信的可分辨”问题之​​一(参见上面的答案)。 - ddimitrov


如果需要在数组检查的基础上搜索对象相等 apache common ArrayUtils,你基本上必须覆盖你的equals和hascode对name对象并使用它,但如果你想使用自定义搜索条件,我想你必须实现自己的方式,并没有内置的java语言支持


0
2018-02-25 17:31





使用内存数据库之类的 Apache Derby 要么 HSQLDB。利用JDBC,JPA或Hibernate,它们都可以满足您的需求。

描述您的代码。然后优化。


0
2018-02-25 20:50





我能想到的更快的方法是创建一个数据结构,它反映这个对象的属性值并保存每个值的内部索引。

搜索值时,此内部数据结构将使用二进制搜索返回索引。

唯一的要求是您的对象必须注册并更新此结构。

类似于以下想象的UML / Python之类的代码:

 // Holds the index number of a given value
 // for instance, name="Oscar" may be at index 42...
 IndexValuePair
     index : Int
     value : String 

     +_ new( value: String, index: Int ) 
          return IndexValuePair( value, index )

 ValuePairComparator --> Comparator 

     + compareTo( a: IndexValuePair, b: IndexValuePair ) : Int 

         return a.value.compareTo( b.value )

 SearchStructure
     - data = Object[] // The original array which contains your applicants
      // a list of arrays each one containing the property value, and the index on "data" where that value appears 
     - dataIndexes =  List(IndexValuePair)[String] // Map<List<IndexValuePair>> 
     - dataIndexexInitialized = false

     // Add an object to this structure
     + addObject( o: Object ) 
          if( ! dataIndexesInitialized, 
              initIndexesWith( o )
          )

          index = data.add( o ) // returns the index at which "o" was inserted
          addToIndexes( o, index ) 

     // Register all the properties values of the given object 
     // along with the index where they appear in the original array 
     - addToIndexes( object: Object, index: Int ) 
           forEach( property in Object , 
              list = dataIndexes[property]
              list.add( IndexValuePair.new( property.value, index ) ) 
           )
     // Create empty array for each property .. 
     - initIndexesWith( object : Object ) 
          forEach( property in object , 
                comparator = ValuePairComparator()
                list = List<IndexValuePair>()
                list.setComparator(  ) 
                dataIndexes[property] =  list
          )
          dataIndexesInitialized = true 


     // Search an object using the given criteria ( a Map<String, String> = key=value ) 
     + search( criteria: String[String] ) : List<Object>

        result = Set<Object>()

        // let's say criteria has:
        // ["name":"Oscar", "lastName"="Reyes"]
       forEach( key in criteria, 
            list = dataIndexes[key]  // "name", "lastname" ..etc. 
            valuePair = list.binarySearch( criteria[key] ) // first Oscar, later Reyes 
            result.add( data[valuePair.index] )
       ) 

       return result

哎呀

我希望这是可以理解的。

关键是,如果你真的要快得多,你必须按属性保存索引

  1. 数据的数组
  2. 每个属性的数组,反过来又具有数据索引

例如,如果您有以下数组:

 a = [ Object(name="Mike", lastName="Z" )
       Object(name="Oscar", lastName="Reyes" ) , 
       Object(name="Rahul", lastName="G" ) , 
       Object(name="Pie", lastName="154" )  ]

他们会有这样的职位:

0 = Mike ... 
1 = Oscar ...
2 = Rahul ...
3 = Pie ...

并且你将有两个(在这种情况下)单独的数组,在排序后将是:

nameArray =  ["Mike=0", "Oscar=1", "Pie=3", "Rahul=2"]

lastNameArray =   ["154=3", "G=2", "Reyes=1", "Z=0"]

当你搜索一个给定的属性时,你拿相应的数组,例如,如果你想搜索姓氏“雷耶斯”你将采取“lastName”数组

 ["154=3", "G=2", "Reyes=1", "Z=0"]

并将对其执行“Reyes”的binarySearch,它将返回位置2处的元素,这反过来将返回索引= 1,这是“Oscar”在原始数组中的位置。

这应该保持O(log n)


0
2018-02-27 01:19





查看ParallelArray类,它满足您的要求,但您需要学习一些函数式编程概念才能有效地使用它。

该类不附带JDK 6,但可能附带JDK 7(正在讨论中)。同时您可以将它用作库 - 从以下位置下载JSR166y软件包: http://gee.cs.oswego.edu/dl/concurrency-interest/

有关详细说明,请参阅本教程: http://www.ibm.com/developerworks/java/library/j-jtp03048.html

这可能听起来很复杂,而且(如果您只是在挖掘高性能多线程算法)。有一个Groovy项目试图围绕Parallel Array包装一个更加用户友好的API,所以你可能也想看看它: http://gpars.codehaus.org/ , http://gpars.codehaus.org/Parallelizer


0
2018-02-27 02:17





Java 8添加了lambda表达式和流API,因此现在支持内置。

Name[] applicants = new Name[4];

applicants[0] = new Name("john", "bob", "rush");
applicants[1] = new Name("joe", "bob", "rushden");
applicants[2] = new Name("jack", "bob", "rushden");
applicants[3] = new Name("jake", "bob", "rushden");

Optional<Name> result = Arrays.stream(applicants)
    .filter(name -> name.middlename.equals("bob") && name.surname.equals("rush"))
    .findAny();

result.ifPresent(name -> System.out.println(name));

这里有很多选择。您可以通过切换获得匹配的名字 .findAny() 至 .findFirst() 或者通过插入并行运行搜索 .parallel() 后 .stream(applicants), 例如。


0
2018-04-19 15:25