如何优化嵌套循环?

时间:2015-12-17 15:55:43

标签: java

我有两个foreach循环。其中一个包含唯一电子邮件列表(外部)。我希望将其作为外循环,并在每次外循环元素与内循环之间存在匹配时将计数增加一。

我的代码现在:

outer: for (String email : emailsOfContactsWhoFitDynConFilter) {
        for (Contact contact : emailClicks.items) {
            String[] contactLink =  (contact.link).split("\\?", -1);
            String queryStringActivity = getQueryStringByName("elqTrackId", contactLink[1]);

            if (email.equals(contact.EmailAddress) && contactLink[0].equals(linkInDynamicContentSplit[0])) {
                if (queryStringActivity !=null && queryStringDynConLink!=null && queryStringActivity.equals(queryStringDynConLink)){
                    count++;
                    break outer; 
                    } else if (queryStringActivity == null || queryStringDynConLink == null) {
                    System.out.println("  -  Missing elqTrackId. But base the same, count++");
                    count++;
                    break outer;
                }
            }
        }
    }

它有效,但问题是这两行:

String[] contactLink =  (contact.link).split("\\?", -1);
String queryStringActivity = getQueryStringByName("elqTrackId", contactLink[1]);

执行次数过多会耗费大量时间。

我可以反转循环,所以它看起来像这样:

outer: for (Contact contact : emailClicks.items) {
            String[] contactLink =  (contact.link).split("\\?", -1);
            String queryStringActivity = getQueryStringByName("elqTrackId", contactLink[1]);
          for (String email : emailsOfContactsWhoFitDynConFilter) {
          if (email.equals(contact.EmailAddress) && contactLink[0].equals(linkInDynamicContentSplit[0])) {
                if (queryStringActivity !=null && queryStringDynConLink!=null && queryStringActivity.equals(queryStringDynConLink)){
                    count++;
                    break outer; 
                    } else if (queryStringActivity == null || queryStringDynConLink == null) {
                    System.out.println("  -  Missing elqTrackId. But base the same, count++");
                    count++;
                    break outer;
                }
            }
        }
    }

这会快得多,但我的count++会比我想要的次数多一次,每封邮件都不会+1

2 个答案:

答案 0 :(得分:2)

这里有几个不错的选择,但第一个是简单地缓存String []。这是为什么你应该使用方法而不是成员的一个宝贵的教训。

我建议使用contact.getLinkCache()方法,实现类似下面的方法。这给你带来了不反复拆分的好处(那里有一个克隆来保护数据,但克隆是一种非常快速的方法,除非你已经确定这个太慢了,你应该去有这个。

class Contact {

    String link;
    String[] linkSplitCache;

    public void setLink(String link) {
        this.link = link;
        this.linkSplitCache = null;
    }

    public String getLink() {
        return link;
    }

    public String[] getLinkCache() {
        if(linkSplitCache == null) {
            linkSplitCache = link.split("\\?",-1);
        }
        // return linkSplitCache; // could corrupt!
        return linkSplitCache.clone(); // pretty fast array copy
    }
}

如果它太慢,那么你会想要某种地图来缓存它,这可能在Contact类之外。

Map<Contact, String[]> linkSplitCache = new HashMap<>();

outer: for (Contact contact : emailClicks.items) {
    String[] contactLink =  linkSplitCache.get(contact);
    if(contactLink == null) {
        contactLink = (contact.link).split("\\?", -1);
        linkSplitCache.put(contact,contactLink);
    }
    // rest of loop here

答案 1 :(得分:0)

在@corsiKlause Ho Ho Ho的大力帮助下,我可以找到解决方案:

Map<String, String[]> linkSplitCache = new HashMap<>();
    int count = 0;
    String[] linkInDynamicContentSplit = linkInDynamicContent.split("\\?", -1);
    String queryStringDynConLink = getQueryStringByName("elqTrackId", linkInDynamicContentSplit[1]);
    if (emailClicks != null && emailsOfContactsWhoFitDynConFilter != null) {
        for (String email : emailsOfContactsWhoFitDynConFilter) {
        inner: for (Contact contact : emailClicks.items) {
                String[] contactLink = linkSplitCache.get(contact.EmailAddress);
                if (contactLink == null){
                    contactLink =  (contact.link).split("\\?", -1);
                    contactLink[1] = getQueryStringByName("elqTrackId", contactLink[1]);
                    linkSplitCache.put(contact.EmailAddress, contactLink);
                }

                if (email.equals(contact.EmailAddress) && contactLink[0].equals(linkInDynamicContentSplit[0])) {
                     if (contactLink[1] !=null && queryStringDynConLink!=null && contactLink[1].equals(queryStringDynConLink)){
                        count++;
                        break inner; // this excludes link clicks which were done
                                // twice by the same person
                    } else if (contactLink[1] == null || queryStringDynConLink == null) {
                        System.out.println("  -  Missing elqTrackId. But base the same, count++");
                        count++;
                        break inner;
                    }
                }
            }
        }
    }

基本上我所做的是使用唯一键HashMap将链接添加到Email address,这样可以确保我不会多次执行相同的操作。没有必要。