识别包含300k +字符串的列表中的重复元素

时间:2012-01-10 05:42:21

标签: java performance arraylist duplicates detection

我有一个包含305899个字符串的列表(这是一个网站的用户名)。删除所有重复项后,数字将下降到172123字符串。

我想查找在该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多分钟。

还有其他有效方法可以解决这个问题吗?只需减少查找和计算重复元素所需的时间吗?

8 个答案:

答案 0 :(得分: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;
}

这应该在大多数机器上执行几秒钟。

答案 1 :(得分: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;
}

它有一些装箱/拆箱开销,但应该比你正在进行的操作快得多,这需要迭代每个唯一名称的整个名称列表。

答案 2 :(得分:2)

您可以尝试使用用户名构建Trie结构。然后找到不同元素的数量(用户名)将是微不足道的。 Trie的代码有点复杂,所以你最好查看资源,看看如何完成实现。

另一方面,考虑到实际情况,您不应该首先拥有此重复列表。我的意思是,如果提供用户名的系统设计得当,那么首先不会存在重复项。

答案 3 :(得分: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;
    }

答案 4 :(得分:0)

最佳解决方案是将所有元素添加到Array中,然后对该数组进行排序。

然后你可以迭代数组,重复项将在数组中彼此相邻放置。

答案 5 :(得分: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;

答案 6 :(得分:0)

使用旨在本机支持此功能的数据结构。将用户名存储在Multiset中,让它自动为您保留频率/计数。

阅读this tutorial以了解multiset的工作方式/

答案 7 :(得分:0)

以下是删除重复项并计算List中重复元素数的最佳方便方法。无需额外的逻辑。

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);*/