对List对象列表属性值的快速搜索
来源:互联网 发布:mac office 2011 汉化 编辑:程序博客网 时间:2024/05/20 17:39
对于数据的搜索已有很多成熟的方案,比如Apace Lucene框架,结合ikanalyer等分词器能实现很复杂和高效的搜索,或直接使用sql语言对数据库关键字进行搜索等。
但这些搜索都很重,对于已经加载完成的数据列表并不适用。
比如有这样一个需求:已经加载了一个班的学生在一个List列表中,要根据学生和姓名和住址做一个模糊搜索。因为数据已经加载到List中,存在于内存中,若再从数据库或网络上去使用关键字取值并不是很优的方案。而一般做法是在查找关键字里,遍历整个列表逐个匹配,但若是如手机上做逐个输入搜索的话会产生大量的循环操作,效率很低。
为此,今天分享一种比较对List列表比较高效的搜索方式。
思路:
1、传入数据源List,并指定要搜索的字段;将这些字段的值拼接成一个字符串,并保存每个对象的值的起始和结束位置:
2、搜索时,先使用正则表达式在保存的搜索字符串找到位置,再利用这些位置在索引数据数组中找到对应对象索引;
具体实现:
package com.fansion;import java.lang.reflect.Field;import java.util.ArrayList;import java.util.List;import java.util.regex.Matcher;import java.util.regex.Pattern;public class FSearchTool { private StringBuffer mKeyWordString = new StringBuffer(); private List<Object> mSearchObjs = new ArrayList<>(); private int[] mIndexes; public FSearchTool(List<? extends Object> objects, String... fields) throws Exception { super(); init(objects, fields); } private void init(List<? extends Object> objs, String... fields) throws Exception { if (objs != null) { mKeyWordString.setLength(0); mSearchObjs.clear(); mSearchObjs = new ArrayList<>(objs); mIndexes = new int[mSearchObjs.size() * 2]; int index = 0; for (int i = 0; i < mSearchObjs.size(); i++) { Object info = mSearchObjs.get(i); // 指定要搜索的字段 String searchKey = getSearchKey(info, fields); // 将该字符串在总字符串中的起终位置保存下来,位置是索引值而非长度 int length = mKeyWordString.length(); mIndexes[index] = length; mKeyWordString.append(searchKey); length = mKeyWordString.length(); index++; // 保存新加搜索字段的索引值 mIndexes[index] = (length > 0) ? length - 1 : 0; index++; } } } /** * 通过反射从对象中取出指定字段的值 */ private String getSearchKey(Object obj, String... fields) throws Exception { StringBuilder searchKeys = new StringBuilder(); Class<? extends Object> clazz = obj.getClass(); try { for (String str : fields) { // 搜索字段使用空格隔开 Field f = clazz.getDeclaredField(str); f.setAccessible(true); Object val = f.get(obj); searchKeys.append(val).append(" "); f.setAccessible(false); } } catch (Exception e) { throw new Exception("取值异常:" + e.getMessage()); } return searchKeys.toString(); } /** * 搜索结果 * * @param keyWords * 搜索的关键字,要去掉首尾的空格 * @return 返回搜索到的对象 */ public List<Object> searchTasks(String keyWords) { List<Object> searchedTask = new ArrayList<>(); int[] searchIndex = getSearchIndex(keyWords); for (int index : searchIndex) { if (index != -1 && index < mSearchObjs.size() * 2) { Object info = mSearchObjs.get(index / 2); if (info != null && !searchedTask.contains(info)) { searchedTask.add(info); } } } return searchedTask; } /** * 找到匹配的索引数据 * * @param keyWords * 搜索的关键字 * @return 在初始化的索引数组的下标数组 */ private int[] getSearchIndex(String keyWords) { Pattern pattern = Pattern.compile(keyWords, Pattern.CASE_INSENSITIVE | Pattern.LITERAL); Matcher matcher = pattern.matcher(mKeyWordString.toString()); ArrayList<Integer> searchResult = new ArrayList<>(); while (matcher.find()) { // 不宜在此处再做循环,否则可能造成循环次数过多错误 searchResult.add(matcher.start()); } int[] searchIndexes = new int[searchResult.size()]; for (int i = 0; i < searchIndexes.length; i++) { int findIndex = findIndex(searchResult.get(i)); searchIndexes[i] = (findIndex / 2) * 2; } return searchIndexes; } /** * 使用二分法找到指定字符位置在索引数组中的位置 * * @param charAt * 字符在整个字符串中的位置 * @return 在索引数组中的位置 */ private int findIndex(int charAt) { int low = 0; int high = mIndexes.length - 1; int mid = -1; while (low <= high) { mid = (low + high) >>> 1; int midVal = mIndexes[mid]; if (midVal < charAt) { low = mid + 1; } else if (midVal > charAt) { high = mid - 1; } else { return mid; } } return mid; }}
简单的使用和测试:
public static void main(String[] args) { List<Student> students = new ArrayList<>(); students.add(new Student("001", "小王", "天府大道一街")); students.add(new Student("002", "小王", "天府大道二街")); students.add(new Student("003", "小红", "天府大道三街")); students.add(new Student("004", "小明", "天府大道四街")); students.add(new Student("005", "小王", "天府大道五街")); students.add(new Student("006", "小王", "软件园南门")); students.add(new Student("007", "小张", "吉泰路")); try { FSearchTool tool = new FSearchTool(students, "name", "address"); System.out.println(tool.searchTasks("明")); } catch (Exception e) { e.printStackTrace(); } }
输出结果:
[Student [id=004, name=小明, address=天府大道四街]]
博客地址:对List对象列表属性值的快速搜索
0 0
- 对List对象列表属性值的快速搜索
- ComparatorChain对List对象的属性排序
- C#对List 的对象的属性进行排序
- 对List<>中对象的属性进行排序。
- 对List中对象属性进行排序
- 对"对象的多个属性"进行匹配搜索"对象数组"的算法
- 获取对象的属性列表
- 无序和有序列表的list-style-type 属性值
- list列表中添加多个【只修改了一个属性的对象】
- 利用list快速的模糊搜索
- Redis对字符串、Hash(对象)、列表(List)处理的操作命令
- 对LIST的对象排序
- Java 对 List 内对象根据对象属性进行排序
- 对谷歌搜索列表的剖析
- Python对列表list的操作
- Property List(属性列表)
- 按bean的属性值对list集合进行排序
- 多个List合并去除list中对象的某个属性值相同的对象
- word中使用bibtex4word插入参考文献。
- 阿里面试心得
- 《Linux/UNIX系统编程手册》第3章读书笔记
- 快排原理
- Spring依赖注入的三种实现方式
- 对List对象列表属性值的快速搜索
- Hadoop配置完善
- Pandas数据读取与显示
- python调用讯飞付费版语音转写
- PHP实现Apriori算法——计算支持度
- 侧滑
- Vue 之 vue-router 路由嵌套不显示问题
- 从0开始制造计算机(1)
- Servlet基础知识复习(1)