2015-12-17 36 views
1

我有兩個foreach循環。其中之一包含唯一電子郵件列表(外部)。我希望將外部循環作爲外部循環,並且每次在外部循環的元素與內部循環之間匹配時增加1。如何優化嵌套循環?

我現在代碼:

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每一個獨立的電子郵件。

+5

我投票關閉這一問題作爲題外話,因爲這個問題將是一個更適合於:http://codereview.stackexchange.com/ –

+1

爲什麼'計數++'執行不同的次數?在交叉連接中,您仍然只在每對中檢查一次。順便說一句,如果將標籤放在循環的上方,而不是同一行代碼,則代碼將更易於閱讀。如果你將其縮小,你的'else if'行也會更清晰。基本上,縮進使得你的代碼現在很難理解。 –

+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 
    } 
} 

如果實在是太慢了,那麼就要某種地圖緩存它,這很可能是跟類之外。

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 
+0

我認爲你有一個很好的觀點,問題在於,'emailClicks.items'作爲一個對象在聯繫方面沒有重複。有重複的是兩個不同的對象,但共享相同的電子郵件地址。但我想我可以用一些調整來使用你的解決方案。 –

+0

我很高興你找到了解決方案。但我忍不住想你應該避免使用'object.member' - 而是使用'object.getMember()'。 – corsiKa

+0

是否有任何實際的原因應該通過getter來完成?我知道這是慣例,但仍然有任何真正的原因?由於這些對象只是'JSON'的反序列化,我不使用任何構造函數,所以我並不需要getter。 –

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,這可以確保我沒有做同樣的操作不止一次在那裏,沒有必要了。