Слово счетчик, используя список слов и несколько текстовых файлов


Моя программа работает с двумя типами файлов. Файл 1 содержит 500 000 уникальных слов. Установить файл 2 содержит 173 текстовые файлы, каждая из которых содержит 500 пунктов, что я наскреб из Википедии. Программа подсчитывает, сколько раз каждое слово из первого файла появляется во втором наборе данных.

Основная проблема у меня заключается в том, что это занимает около 4 секунд на слово в процессе, так что это займет около 24 дней, чтобы завершить все 500к слов в core5 7-й Gen 8 ГБ оперативной памяти ноутбука. Можно ли сделать его более эффективным процесс?

Я все еще учусь Java, так что мои знания не так обширны. Я с помощью Java 8, с IntelliJ как мой язь.

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

public class Main {

public static void main(String[] args) {

    //This is the map that will contain each word
    Map<String, Integer> map = new HashMap<>();
    //int that will count how manny times the word is in the File set 2
    int wordCounter = 0;
    //List that contain arround 500k unrepeted words
    List<String> list = new ArrayList<>();
    //List that contains the current file words
    List<String> list1 = new ArrayList<>();


    try {
        //scans the file that contains the 500k unrepeted words
        Scanner s = new Scanner(new File("C:\\Users\\filepath"));
        //while loop that add the words to a list so it can manipulate it latter on
        while (s.hasNext()) {
            list.add(s.next());
        }
        //random output to see the Set size
        System.out.println(list.size());


        //main loop that will cheek each word in the 500k file
        for (int i = 0; i < list.size(); i++) {
            //loop to se each file of words
            for (int j = 0; j < 100; j++) {
                try {
                    //read each file
                    Scanner d = new Scanner(new File("C:\\Users\\filepath" + j));
                    //add the information of each file
                    while (d.hasNext()) {
                        list1.add(d.next());
                    }
                    d.close();
                    //this code counts the number of words in all the files a
                    wordCounter = wordCounter + Collections.frequency(list1, list.get(i).toLowerCase());
                    //clears the list so it has more space and not run out of it
                    list1.clear();

                } catch (IOException k) {
                    k.printStackTrace();
                }
            }
            //adds the information to the map
            map.put(list.get(i), wordCounter);
            //this sorts the information and discard the words that only has 1 or less matches
            if (wordCounter > 1) {
                try {
                    FileWriter fw = new FileWriter("C:\\Users\\filePath", true);
                    PrintWriter pw = new PrintWriter(fw);
                    pw.append("\n");
                    pw.append(map.toString());
                    pw.close();

                } catch (IOException f) {
                    f.printStackTrace();
                }
            }
            //this clean the map so it doesnt run out of memory
                map.clear();
            //resets the counter to 0
                wordCounter = 0;
                //simple display so it seems nice
            System.out.println(i);

        }
    } catch (IOException f){
            f.printStackTrace();
        }



        }

    }

Где-то я читал, что из-за Java с использованием виртуальной машины, она делает обработку данных намного медленнее. Это будет что-то рассмотреть?



899
2
задан 26 февраля 2018 в 08:02 Источник Поделиться
Комментарии
2 ответа

Вы должны попробовать, чтобы переключить внутренней и наружной петлей, потому что он будет значительно быстрее прочитать все статьи в Википедии и подсчет частотности слов для всех 500к слова (вы в любом случае есть список 500к слово в памяти все время). Что вы делаете сейчас читает 500к раз все статьи в памяти, которая отнимает много времени.

Суммируя все случаи использования слова, вы можете использовать карту, которая уже существует. Просто зачитал сумма для данного слова, добавить вхождений в нынешней статье и записать его обратно на карту. Сейчас вы не только писать по одной записи в карте, преобразовать его в строку и очистить его сразу после этого. Я полагаю, у вас была мысль сделать так, как я описал.

Не беспокойтесь о скорости исполнения Java в целом, потому что код компилируется (как раз-в-времени компиляции) в машинный код, в конце концов.

2
ответ дан 26 февраля 2018 в 09:02 Источник Поделиться

Во-первых, вы должны действительно использовать более осмысленные имена переменных.

wordCount говорит много больше, чем map, uniqueWords намного больше, чем list И же для wordsInCurrentFile вместо list1.

Просто переименование это делает его гораздо легче следовать тому, что ваша программа делает.


Вы должны следовать совету Маркуса, чтобы перевернуть петли. Во внешнем цикле, вы должны перебирать каждый файл. А потом для каждого файла, подсчет вхождений каждого из слов.

Мы также можем оптимизировать использование наших переменных немного, поэтому мы даже не нужны 2 списков.

Вот главная мысль:

Map<String, int> wordCount = new HashMap<>();
File wordFile = new File( ...); //open the file with unique words
while(wordFile.hasNext()){
wordCount.put(wordFile.next(), 0);
}

На данный момент у нас есть запись в нашей карте посчитать для каждого из 500 тысяч слов.

for( each file with wiki text) {

перебирать каждый файл в космическом цикле. Либо таким же образом, открытие файла, как ты на основе фиксированного имя и номер прилагается. Или положить все файлы в определенной директории и в Java перебрать все файлы, которые вы найдете в этом каталоге.

    while(file.hasNext()){
String word = file.next();

На данный момент мы пробегаем за каждое слово в файл и хотите обновить их общее количество.

        Map<String, Integer> wordCount = new HashMap<>();
if (wordCount.containsKey(word)) {
wordCount.put(word, wordCount.get(word)+1);
}
}
}


Он также может быть стоит посмотреть как получить список всех файлов в директории в Java 8 (я не знаком с этим сам еще).

И это также хорошая идея, чтобы посмотреть, как использование try-с-ресурсами, начиная с Java 7, которая помогает регулировать закрытие файла после того как вы закончите с ним. Как ты это сейчас написал не правильно закрыть файл, если вы столкнулись с ошибкой.

0
ответ дан 27 февраля 2018 в 03:02 Источник Поделиться