在大文件中查找字数并对结果进行排序

时间:2013-03-13 15:19:48

标签: java data-structures

我有一个包含各种字符串的大文件。我需要解析文件并找到文件中存在的各种单词的字数。在那之后,我需要按照他们的计数的顺序排列这些单词。

我的方法是解析文件并将单词存储在Hashmap中,其中word是key,count是value。在我们继续解析文件时,计数将会更新。解析完成后,我将根据计数对集合进行排序。

上述方法非常简单,并未考虑文件很大。

我应该采取哪些措施来处理大文件?

4 个答案:

答案 0 :(得分:1)

如果您要拥有多个主题,请不要使用HashMap,而是使用ConcurrentHashMap代替javadoc

如果Integer值已经存在,您仍需要执行某种检查。有关该流程的详细信息,请参阅this帖子。

在填充完地图后,请参阅this帖子对地图进行排序。

答案 1 :(得分:1)

所以,请在评论中对我的陈述进行更多澄清:

我们假设你有大文件。它需要N次操作才能逐字逐句地读取它。到目前为止,这将是你的瓶颈,因为I / O通常很慢。

对于您的点票方案,您使用Map<String, Integer>。你看到的每个单词都会放入Map中,如果你不止一次遇到一个特定的单词,你会添加1.通常,添加一个特定的键值对是恒定时间(HashMap),并弄清楚你是否可以在地图中放置一个新的Integer也是不变的。

因此,计算文件中单词的整体运行时性能为O(N)+ C,其中N主要是由于I / O.

现在,假设你使用十个线程。您将大文件切割成十个块,并让每个线程将其值插入ConcurrentHashMap。您的整体运行时复杂性没有改变,除了它(可能)减少了10倍。

使用其他线程的运行时将为O(t(1/10)N)+ C,仍然会减少为O(N)+ C.

如果你可以改变使用的线性扫描方法比线性时间更有效,那么唯一可以让它更加效率的方法就是。

答案 2 :(得分:1)

首先,我使用Map来确定字数:

    String[] words = {"one", "two", "three", "two", "three", "three"};
    Map<String, Integer> map = new HashMap<String, java.lang.Integer>();
    for (String word : words) {
        int count = 0;
        if (map.containsKey(word)) {
            count = map.get(word);
        }
        map.put(word, ++count);
    }
    System.out.println(map);
    --> output: {two=2, one=1, three=3}

然后,我会使用TreeMap或新的“自定义”键/值类来按计数排序:

使用TreeMap

private static void sortUsingTreeMap(Map<String, Integer> map) {
    TreeMap<String, Integer> sorted = new TreeMap<String, Integer>(new MyComparator(map));
    sorted.putAll(map);
    System.out.println(sorted);
}

static class MyComparator implements Comparator<String> {
    private Map<String, Integer> map;

    MyComparator(Map<String, Integer> map) {
        this.map = map;
    }

    @Override
    public int compare(String o1, String o2) {
        return map.get(o1).compareTo(map.get(o2));
    }
}
--> output: {one=1, two=2, three=3}

使用新的键/值类:

private static void sortUsingKeyValueClass(Map<String, Integer> map) {
    class KeyValue implements Comparable<KeyValue> {
        private final Integer count;
        private final String word;

        public KeyValue(Integer count, String word) {
            this.count = count;
            this.word = word;
        }

        @Override
        public int compareTo(KeyValue o) {
            return count.compareTo(o.count);
        }

        @Override
        public String toString() {
            return word + "=" + count;
        }
    }

    List<KeyValue> keyValues = new ArrayList<KeyValue>();
    for (String word : map.keySet()) {
        keyValues.add(new KeyValue(map.get(word), word));
    }
    Collections.sort(keyValues);
    System.out.println(keyValues);
}
--> output: [one=1, two=2, three=3]

我还要补充一点,我会推迟添加线程,直到我发现它必须具有明显的性能。正如其他人所说的那样,通过同时处理结果不会保存很差的实现。

答案 3 :(得分:0)

正如评论中所说的那样,线程对于决胜局的情况非常有用,在这种情况下,您希望解决方案比其他人的解决方案快一点。如果在其中运行的内容非常慢,则线程是无用的。

对于问题的第一部分,散列映射最适合时间复杂度。

对于问题的第二部分,我将使用一个集合,一个二维数组,以及您在第一部分中使用的数据结构。如果您再次解析文件,将每个新单词添加到集合并在已创建的散列映射中检查其字数,则可以将每个单词存储在其单词计数的索引位置。在那之后,只需向后遍历数组,你就可以按照数量顺序排列。