从非诚勿扰看数据索引,优化代码小妙招
  VaQwjxXSVONU 2023年11月02日 46 0


抛出问题

假如有两组数据,这六个人去参加非诚勿扰,需要做一个配对。数据如下:

List<User> usersA = new ArrayList<>();

usersA.add(new User("1", "吕布", "10"));

usersA.add(new User("2", "刘备", "11"));

usersA.add(new User("3", "孙悟空", "12"));



List<User> usersB = new ArrayList<>();

usersB.add(new User("10", "貂蝉", "1"));

usersB.add(new User("11", "孙尚香", "2"));

usersB.add(new User("12", "紫霞", "3"));

比如 usersA.add(new User("1", "吕布", "10"));

1是吕布自己的ID,10是配对方的ID。假设现在有个需求,需要返回一个结果集,返回“吕布-貂蝉”这样的数据。首先想到的肯定就是双层for,这简直就是理所当然的事情。

int loopCount = 0;
for(User userA : usersA) {
for(User userB : usersB) {
loopCount++;
if(userB.getUid().equals(userA.getCoupleId())) {
System.out.println( String.format("%s-%s",userA.getUname(),userB.getUname()));
}

}
}

结果:

吕布-貂蝉
刘备-孙尚香
孙悟空-紫霞
一共循环9次

逻辑清晰,简单易懂,完全没有问题。

优化1

一个最简单的优化思路就是,比如吕布已经找到了貂蝉,那么应该立刻跳出循环才对。因为吕布已经找到貂蝉了,就没必要再去找孙尚香。int loopCount = 0;

int loopCount = 0;
for(User userA : usersA) {
for(User userB : usersB) {
loopCount++;
if(userB.getUid().equals(userA.getCoupleId())) {
System.out.println( String.format("%s-%s",userA.getUname(),userB.getUname()));
break;
}

}
}

加一个break就完事儿了。

吕布-貂蝉
刘备-孙尚香
孙悟空-紫霞
一共循环6次

从9次减少到6次,非常大的提升。

优化2

纳尼,还能优化?肯定的,比如吕布匹配到貂蝉后,下一个循环,刘备还是会匹配到貂蝉,这就不合理,所以不妨把匹配到的对象直接从List删去,就不会出现重复匹配的情况了。

非诚勿扰的规则也是,牵手成功后就直接下场了,不会继续留在舞台上。所以,加一个remove操作就很有必要。

for(User userA : usersA) {

for(User userB : usersB) {

loopCount++;

if(userB.getUid().equals(userA.getCoupleId())) {

System.out.println( String.format("%s-%s",userA.getUname(),userB.getUname()));

usersB.remove(userB);

break;

}

}

}

我靠,直接到3次了,这肯定是最优解了吧?然而,并不是。因为List里面user的顺序是正好的,吕布对貂蝉,刘备对孙尚香,猴子对露娜。

可实际情况,哪有这么巧合的事情??

比如我随便打乱一下顺序,就不同了。

List<User> usersB = new ArrayList<>();

usersB.add(new User("12", "紫霞", "3"));

usersB.add(new User("10", "貂蝉", "1"));

usersB.add(new User("11", "孙尚香", "2"));

这样的结果就是循环5次,那如果数据更多呢?比如第一个数据要匹配到最后一个才对得上,那效率也就太低了。

优化3

虽然用for循环给人感觉是天经地义,但是不妨换个思路,男嘉宾为什么非要一个个去找呢,比如吕布,一眼扫过去看到貂蝉,直接牵走不就完事了吗?

所以,我们可以给女嘉宾建立索引,最简单的办法就是用Map。

int loopCount = 0;

Map<String, String> usersMap = new LinkedHashMap<String, String> ();
for (User userB : usersB) {

loopCount++;

usersMap.put(userB.getUid(), userB.getUname());

}
for (User userA : usersA) {

loopCount++;

System.out.println(String.format("%s-%s", userA.getUname(), usersMap.get(userA.getCoupleId())));

}

结果:

吕布-貂蝉
刘备-孙尚香
孙悟空-紫霞
一共循环6次

假如两个列表的长度分别是m和n,那么不管其中的顺序如何,循环的深度永远是固定的m+n。虽然还是比不上上面的最佳情况n次,但是当m和n特别大的时候,效率就立刻突显出来了。

当然了,因为用了Map,牺牲了一点点内存,算是空间换时间吧。

实际应用场景

项目中的实际应用有很多,比如数据字典,很多项目会在SpringContext启动的时候,就把字典表加载到内存。当出现表字段需要做转换的时候,直接查表,效率非常可观。(和left join比起来)

比如,我有一个xml:

<grid id="grid0" class="com.service.UserService" method="getList" parameters="" resulttype="com.answer.entity.User"> 
<column id="uid">
用户编号
</column>
<column id="uname">
用户名称
</column>
<column id="role" datadic="role">
角色
</column>
</grid>

这是自定义的标签,可以通过反射,xml解析的方式做一个小型的解析框架。用到了jsoup,做一个测试类:

public class JspTest {

public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {

Map<String, Map<String, Object>> datadics = new HashedMap();
Map<String, Object> roleDict = new HashedMap();
roleDict.put("1", "射手");
roleDict.put("2", "法师");
datadics.put("role", roleDict);

File file = new File("D:\\eclipse-mars\\workspace2\\answer\\WebContent\\table.xml");
Document doc = Jsoup.parse(file, "UTF-8");
Elements grids = doc.getElementsByTag("grid");

List<String> colums = new ArrayList<String>();
List<List<Object>> rows = new ArrayList<List<Object>>();

for (Iterator<Element> iterator = grids.iterator(); iterator.hasNext(); ) {
Element grid = (Element) iterator.next();
String className = grid.attr("class");
String method = grid.attr("method");
String resultType = grid.attr("resultType");

Class<?> clazz = Class.forName(className);
Class resultClass = Class.forName(resultType);
Method method2 = clazz.getMethod(method);

List result = (List) method2.invoke(clazz.newInstance());

Elements columns = grid.getElementsByTag("column");
int index = 0;

for (int i = 0; i < result.size(); i++) {
Element e = (Element) columns.get(i);

String colName = e.text();
colums.add(colName);
List row = new ArrayList<>();
rows.add(row);

Object object = result.get(index++);
for (int j = 0; j < columns.size(); j++) {
String id = columns.get(j).attr("id");
String DATADIC = columns.get(j).attr("DATADIC");
Map<String, Object> map = datadics.get(DATADIC);
Object fieldValue = null;
fieldValue = ReflectUtil.getFieldValue(object, id);
if (map != null) {
fieldValue = map.get(String.valueOf(fieldValue));
}

rows.get(i).add(fieldValue);
}
}
}

StringBuffer sb = new StringBuffer("\n");
for (Iterator iterator = colums.iterator(); iterator.hasNext(); ) {
String column = (String) iterator.next();
sb.append("");

}
sb.append("\n");


for (Iterator iterator = rows.iterator(); iterator.hasNext(); ) {
List<Object> row = (List<Object>) iterator.next();
sb.append("");
for (Iterator iterator2 = row.iterator(); iterator2.hasNext(); ) {
Object string = iterator2.next();
sb.append("");

}
sb.append("");
sb.append("\n");
}

sb.append("");
sb.append(column);
sb.append("");
sb.append(string);
sb.append("");

grids.get(0).replaceWith(Jsoup.parse(sb.toString()).body());
System.out.println(doc);
FileUtil.writeString(doc.toString(), new File("D:\\eclipse - mars\\workspace2\\answer\\WebContent\\table.html "), " GBK ");
}
}

最终生成一个html,效果如下:

用户编号

用户名称

角色

001

鲁班七号

射手

002

后裔

射手

001

张良

法师

其中,角色已经默认用字典转化了,很多框架内部应该是做了类似的事情。当然,主要是一些老的框架,毕竟现在还在用jsp标签的系统已经不多了。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  SBowDWXjb0NT   2023年11月30日   40   0   0 redis线程池数据
VaQwjxXSVONU
最新推荐 更多