Перевод генератора таблиц вероятности Ruby для символов в Java - PullRequest
0 голосов
/ 24 декабря 2018

Я хочу создать свой собственный относительно продвинутый генератор случайных имен, и единственный ресурс, который мне удалось найти, который не просто случайно объединяет слоги, написан на Ruby.

В примере на Ruby таблица вероятностных пар из двух букв создается из текстового файла, полного имен.Он использует это для генерации случайных имен.Создание этой таблицы вероятностей - это то, что я пытаюсь сделать здесь.

Проблема в том, что я никогда не изучал Ruby, и хотя я могу немного его собрать, я наткнулся на стену.

Меня больше всего смущают последние несколько строк в примере.Начиная с утверждения frequencies.sort.each {|key, value| final[key] = (value / letter_total_count[key[0]]) }.

Мне кажется, что эта строка предназначена для изменения «окончательного» хэша путем ввода произведения всех значений рубиновых «частот» хэша, деленных на значение другого хэша Ruby.,Второй хэш называется «letter_total_count»

Проблема в том, что автор комментирует выше «letter_total_count», говоря: «получить общее количество каждой отдельной буквы».Поскольку хэш-«частоты», кажется, включает в себя только двухсимвольные массивы для своих значений ключа, он не имеет такого же количества ключевых значений, как хэш-код «letter_total_count».Это затрудняет итерацию и того, и другого одновременно.

Я уверен, что мое понимание где-то здесь неверно, но, надеюсь, вы поймете, почему я запутался в этом.

Что на самом деле делает упомянутое утверждение и как я могу реализовать его в Java?

Оригинальный пример Ruby был найден на этой странице блога .

Оригинальный пример в Ruby:

# simple scripting to generate probability tables from a file

# PARAMETERS
# this script takes two parameters, the first is the input file 
# and the second is the output file

require "yaml"

input_file = ARGV[0]
output_file = ARGV[1]

# treat all letters as well as spaces
chars = ('a'..'z').to_a.push(' ')

last_char_read = " "
frequencies = Hash.new(0.0)

# parse the file to read letter pair frequencies
File.open(input_file) do |file|
    while char = file.getc
        if ('a'..'z').to_a.include?(char.downcase)
            if chars.include?(last_char_read.downcase)
                frequencies[last_char_read.downcase + char.downcase] += 1
            end
        end

        last_char_read = char
    end
end

# get the total count of each single letter
letter_total_count = Hash.new(0.0)
frequencies.each {|key, value| letter_total_count[key[0]] += value}  
letter_total_count[frequencies.keys.last[1]] += 1

# the final hash will contain our, ahem, final result
final = Hash.new(0.0)
frequencies.sort.each {|key, value| final[key] = (value / letter_total_count[key[0]])  }  

# make a running total 
chars.each do |first_letter|
    running_total = 0.0

    ('a'..'z').each do |second_letter| 
        if final.key? first_letter + second_letter
            original_value = final[first_letter + second_letter] 
            final[first_letter + second_letter] += running_total
            running_total += original_value
        end
    end
end

# output to file for later use
File.open(output_file, "w") {|file| file.puts YAML::dump(final)}

Моя попытка в версии Java:

public class MCVE {

public static void main(String[] args) throws IOException {
    String addr = "./res/text_files/";

    File file = new File(addr + "human_name_samples");
    String text = new Scanner(file).useDelimiter("\\Z").next();
    text = text.replaceAll("[^a-zA-Z]", " ").toLowerCase();
    char[] charArr = text.toCharArray();

    // read letter pair frequencies
    HashMap<char[], Integer> frequencies = new HashMap<>();
    char lastCharRead = ' ';
    for (int i = 0; i < charArr.length; i++) {
        char[] tempArr = {lastCharRead, charArr[i]};

        if (frequencies.containsKey(tempArr))
            frequencies.replace(tempArr, frequencies.get(tempArr) + 1);
        else
            frequencies.put(tempArr, 1);

        lastCharRead = charArr[i];
    }

    // get the total count of each single letter
    HashMap<Character, Integer> letterTotalCount = new HashMap<>();
    for (HashMap.Entry<char[], Integer> entry : frequencies.entrySet()) {
        char[] tempArr = entry.getKey();

        if (letterTotalCount.containsKey(tempArr[0]))
            letterTotalCount.replace(tempArr[0], letterTotalCount.get(tempArr[0]) + 1);
        else
            letterTotalCount.put(tempArr[0], 1);

        if (letterTotalCount.containsKey(tempArr[1]))
            letterTotalCount.replace(tempArr[1], letterTotalCount.get(tempArr[1]) + 1);
        else
            letterTotalCount.put(tempArr[1], 1);
    }

    // holds final result
    HashMap<char[], Double> finalMap = new HashMap<>();
    for (HashMap.Entry<char[], Integer> entry : frequencies.entrySet()) {
        char[] tempArr = entry.getKey();
        // this is where I'm confused.
        // trying to copy `frequencies.sort.each {|key, value| final[key] = (value / letter_total_count[key[0]])  }`
        double tempDouble = entry.getValue() / letterTotalCount.get(entry.getKey());
        finalMap.put(tempArr, tempDouble);
    }
}
}
...