Я хочу создать свой собственный относительно продвинутый генератор случайных имен, и единственный ресурс, который мне удалось найти, который не просто случайно объединяет слоги, написан на 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);
}
}
}