【问题标题】:Predicate Searching in JavaJava中的谓词搜索
【发布时间】:2023-03-28 04:36:01
【问题描述】:

不太清楚这个问题该如何措辞。 我想知道是否有一种方法可以检查自定义 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 类,它允许快速搜索数组。 这个速度很重要。

【问题讨论】:

  • 除非必须,否则不应使用数组,在 99.99999% 的情况下,列表是更好的解决方案。
  • 为什么是“Java 对象问题”?

标签: java search arrays rules predicates


【解决方案1】:

没有内置支持,但Apache CollectionsGoogle Collections 都提供对集合的谓词支持。

您可能会发现this question 及其答案很有帮助。与这篇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));

【讨论】:

  • 是否有任何地方可以获得关于使用 google 集合中的谓词的教程或更多示例?
  • Java 8 添加了内置支持。我添加了一个示例作为答案。
【解决方案2】:

流和 lambda

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() 或通过在.stream(applicants) 之后插入.parallel() 来并行运行搜索来匹配第一个名称。

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 只是一个小提示,但是您所指的结构树和地图仍然基于数组。他们只是使用特定的方法来搜索数组。
    • 有一些方法可以更快地搜索数组,首先 - 对数组进行一次排序将加快从线性到对数的搜索,其次 - 这是“令人尴尬的可并行化”问题之一(请参阅上面的答案)。
    【解决方案4】:

    如果您需要基于数组检查apache common ArrayUtils上的对象相等性进行搜索,您基本上必须覆盖名称对象的equals和hascode并使用它,但是如果您想使用自定义搜索条件,我猜您有以自己的方式实现,并且没有内置的 java 语言支持

    【讨论】:

      【解决方案5】:

      使用内存数据库,例如 Apache Derbyhsqldb。利用 JDBC、JPA 或 Hibernate,它们都可以满足您的需求。

      分析您的代码。然后优化。

      【讨论】:

        【解决方案6】:

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

        当一个值被搜索时,这个内部数据结构将使用二分搜索返回索引。

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

        类似于以下虚构的 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"]
        

        当你搜索一个给定的属性时,你会使用相应的数组,例如,如果你想搜索姓氏“Reyes”,你会使用“lastName”数组

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

        并且将对“Reyes”执行二进制搜索,这将返回位置 2 处的元素,该元素又将返回索引 = 1,即“Oscar”在原始数组中的位置。

        这应该使事情保持在 O(log n) 以内

        【讨论】:

          【解决方案7】:

          看看 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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-10-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-02-26
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多