2012-01-10 42 views
3

我有一個包含305899個字符串(這是網站的用戶名)的列表。刪除所有重複項後,數字將降至172123字符串。在包含300k +字符串的列表中識別重複的元素

我想找到一個特定的字符串(用戶名)在該ArrayList中重複多少次。我寫了一個簡單的氣泡排序類型邏輯,但它太慢了。

private static Map<String, Integer> findNumberOfPosts(List<String> userNameList) { 
    Map<String, Integer> numberOfPosts = new HashMap<String, Integer>(); 
    int duplicate = 0; 
    int size = userNameList.size(); 
    for (int i = 0; i < size - 1; i++) { 
     duplicate = 0; 
     for (int j = i + 1; j < size; j++) { 
      if (userNameList.get(i).equals(userNameList.get(j))) { 
       duplicate++; 
       userNameList.remove(j); 
       j--; 
       size--; 

      } 
     } 
     numberOfPosts.put(userNameList.get(i), duplicate); 
    } 

    return numberOfPosts; 
} 

然後,我把它改成這樣:

private static Map<String, Integer> findNumberOfPosts(List<String> userNameList) { 
    Map<String, Integer> numberOfPosts = new HashMap<String, Integer>(); 

    Set<String> unique = new HashSet<String>(userNameList); 

    for (String key : unique) { 
     numberOfPosts.put(key, Collections.frequency(userNameList, key)); 
    } 

    return numberOfPosts; 
} 

這是很慢也是如此。當我的意思是慢時,通過列表需要30分鐘以上。

有沒有其他有效的方法來處理這個問題?只需減少查找和計算重複元素所需的時間?

+0

可以兩個有相同的用戶名,爲什麼重複? – Noor 2012-01-10 05:46:49

+0

「我寫了一個簡單的氣泡排序類型邏輯,但速度太慢了。」 - 是的,這就是泡泡分類的問題:它是一個困難的O(N^2)每次都會給你。 – 2012-01-10 05:48:27

+1

我建議你將它保存在數據庫表中,然後在用戶名上得到COUNT,這會更快更簡單。 – 2012-01-10 05:54:19

回答

4

findNumberOfPosts方法是在正確的軌道上,但您的實現做不必要的工作負荷。
試試這個:

private static Map<String, Integer> findNumberOfPosts(List<String> userNameList) { 
    Map<String, Integer> numberOfPosts = new HashMap<String, Integer>(); 

    for (String userName : userNameList) { 
     Integer count = numberOfPosts.get(userName); 
     numberOfPosts.put(userName, count == null ? 1 : ++count); 
    } 
    return numberOfPosts; 
} 

這應該在大多數機器上幾秒鐘執行。

+0

+1。但是使用Multiset不是更好嗎? – 2012-01-10 06:06:36

+0

真棒!現在它運行速度要快得多。但我有一個天真的問題。例如,我的列表中有3個「foo」。現在我不明白的是,numberOfPosts應該有(foo,1),(foo,2)和(foo,3)3個「foo」嗎?因爲HashMap允許重複條目。 你的邏輯工作很好,但我不明白爲什麼只有1條3「foo」的條目?非常感謝您的時間! – javaCity 2012-01-10 06:08:06

+1

@javaCity HashMap不允許重複條目。當你把新的計數,它取代了舊的。 – 2012-01-10 06:10:35

2

您可以嘗試從用戶名中構建Trie結構。然後,找到不同元素(用戶名)的數量是微不足道的。 Trie的代碼有點複雜,所以你最好查看資源,看看如何完成實現。

在其他的想法,考慮到實際情況,你不應該有第一個這個重複列表。我的意思是,如果系統提供的用戶名是正確設計的,那麼重複將不存在在第一位。

+1

那麼在這種情況下,我沒有給出太多情景。我有一個用戶發佈文本和用戶名的文本文件。所以我想知道用戶通過該文件發佈了多少次。 另外,我會看看Trie結構。謝謝:) – javaCity 2012-01-10 05:55:36

+0

@javaCity:不確定你是否有權訪問正在生成文件的系統,如果你這樣做,爲什麼不只是在一個新的文章發佈後更新計數。如果您無法控制生成文件並假設文件會隨時間增加,您可以維護不同的計數策略以檢測出新文章,例如記住您上一次處理的行並繼續處理。 – 2012-01-10 06:01:24

+1

謝謝。我沒有訪問該系統。我想我已經找到了比我之前做的更快的解決方案。感謝您的幫助! – javaCity 2012-01-10 06:05:14

3

看看你的第二個方法的這種變化工作速度快:

private static Map<String, Integer> findNumberOfPosts(
     List<String> userNameList) { 
    Map<String, Integer> numberOfPosts = new HashMap<String, Integer>(); 

    for (String name : userNameList) { 
     Integer count = numberOfPosts.get(name); 
     numberOfPosts.put(name, count == null ? 1 : (1 + count)); 
    } 

    return numberOfPosts; 
} 

它有一些裝箱/拆箱的開銷,但應該比你在做什麼,這需要遍歷整個列表的操作速度快了很多每個唯一名稱的名稱。

0

最好的解決方案是將所有元素添加到數組,然後對該數組進行排序。

然後,您可以迭代數組,並將重複項放在數組中相鄰。

0

你應該嘗試改進第一個實現:對於每個條目你迭代整個列表。如何像:

Map<String, Integer> map; 
for (String username : usernames) { 
    if (!map.containsKey(username)) { 
     map.put(username, new Integer(0)); 
    } else { 
     map.put(username, new Integer(map.get(username).intValue() + 1)); 
    } 
} 
return map; 
+0

不完全...測試它,看看會發生什麼 – Bohemian 2012-01-10 05:56:20

+0

是的,我剛剛看到我的錯誤 – personak 2012-01-10 05:57:04

+0

我認爲你的意思是做map.put。 – 2012-01-10 05:57:36

0

使用設計用於本機支持的數據結構。將用戶名保存在Multiset中,讓它自動爲您保留頻率/計數。

閱讀this tutorial瞭解如何多集作品/

+0

謝謝,會做。 – javaCity 2012-01-10 06:16:44

1

這正好速度甚至超過了波西米亞的:

private static Map<String, Integer> findNumberOfPosts(List<String> userNameList) { 

     Map<String, Integer> numberOfPosts = new HashMap<String, Integer>(); 

     for (String userName : userNameList) { 
      if (!numberOfPosts.containsKey(userName)) { 
       numberOfPosts.put(userName, Collections.frequency(userNameList, userName)); 
      } 
     } 

     return numberOfPosts; 
    } 
+0

我很抱歉,在比較和測試您的代碼對波西米亞的代碼後,他的代碼運行得比您的代碼快得多。但我感謝你的努力。謝謝! – javaCity 2012-01-10 06:25:09

+0

你說得對 - 我應該說「對於某些數據集」:-) – millhouse 2012-01-10 22:18:06

0

以下是消除重複和計數的重複元素的數量最好和方便的方法名單。不需要額外的邏輯。

List<String> userNameList = new ArrayList<String>(); 
// add elements to userNameList, including duplicates 

userNameList.add("a"); 
userNameList.add("a"); 
userNameList.add("a"); 
userNameList.add("a"); 

userNameList.add("b"); 
userNameList.add("b"); 
userNameList.add("b"); 
userNameList.add("b"); 

userNameList.add("c"); 
userNameList.add("c"); 
userNameList.add("c"); 
userNameList.add("c"); 

int originalSize=userNameList.size(); 

HashSet hs = new HashSet(); //Set would handle the duplicates automatically. 
hs.addAll(userNameList); 
userNameList.clear(); 
userNameList.addAll(hs); 

Collections.sort(userNameList); //Sort the List, if needed. 

//Displays elements after removing duplicate entries. 
for(Object element:userNameList) 
{ 
    System.out.println(element); 
} 

int duplicate=originalSize-userNameList.size(); 

System.out.println("Duplicate entries in the List:->"+duplicate); //Number of duplicate entries. 

/*Map<String, Integer> numberOfPosts = new HashMap<String, Integer>(); //Store duplicate entries in your Map using some key. 
numberOfPosts.put(userNameList.get(i), duplicate); 

return(numberOfPosts);*/ 
+0

這是真的。但我不想刪除重複的條目。我只想計算一個特定對象重複的次數。這個問題已經解決了,但是感謝你的努力。 – javaCity 2012-01-10 06:38:39

相關問題