随笔 - 434,  文章 - 0,  评论 - 463,  阅读 - 46万

抛出问题

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

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标签的系统已经不多了。

posted on   剽悍一小兔  阅读(16)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示