Java 中的谓词搜索
-
22-09-2019 - |
题
不太确定如何表达这个问题。我想知道是否有一种方法可以检查自定义 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
,ETC
但更多的是一个内置的 java 类,允许快速搜索数组。这个速度非常重要。
解决方案
没有内置支持,但是 阿帕奇集合 和 谷歌收藏 两者都提供对集合的谓词支持。
你可能会发现 这个问题 其答案很有帮助。与此相同 开发者网 文章。
例如使用 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));
其他提示
通过阵列搜索和“速度是非常重要的”真的不一起去。除非,如果你的阵列将是非常小的,然后通过一个数组搜索决不会快。这相当于在一个数据库中,性能全表扫描的,不管你怎么去了解它会很差。迅速找到事情的关键是使用索引结构。你仍然可以有一个数组,如果你确实需要它,但搜索应该用另一种数据结构来完成。退房散列或基于树的集合,因为他们的方式,使得它非常快速检索组织数据。 TreeSet中,TreeMap中,HashSet的,HashMap中,在散列密钥等散列索引数据,树木是类似的,但其也将数据存储在排序顺序。
如果您需要搜索基于在阵列检查apache common ArrayUtils
对象平等,你基本上要重写你的equals和hascode的名字对象,并使用它,但如果你想使用自定义的搜索条件,我想你必须实现自己的路,并没有内置在Java语言支持
我能想到的更快的方法是创建一个数据结构,该数据结构反映该对象的属性值并保存每个值的内部索引。
当搜索一个值时,这个内部数据结构将使用二分搜索返回索引。
唯一的要求是您的对象必须注册并更新此结构。
类似于以下虚构的 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
哎呀
我希望这是可以理解的。
关键是,如果你真的想要这么快,你必须按属性保存索引
- 数据的数组
- 每个属性都有一个数组,该数组又包含数据索引
例如,如果您有以下数组:
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) 以下
看的ParallelArray类,它满足您的要求,但你需要学习一点的函数式编程概念,有效地使用它。
类不附带JDK 6,但可能附带JDK 7(下的讨论)。同时,你可以使用它作为一个库 - 从下载JSR166y包: http://gee.cs.oswego.edu/dl/concurrency-interest/
请参阅本教程详细的解释: http://www.ibm.com/developerworks/java/library/ J-jtp03048.html
这可能听起来很复杂,这是(如果你arew只是在高性能多线程算法挖掘)。还有它试图环绕并行阵列更人性化的API,所以你可能要ttake看看它还有一个Groovy项目:的 http://gpars.codehaus.org/ , HTTP:// gpars。 codehaus.org/Parallelizer
爪哇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)
,例如并行运行搜索。