Java 8 Stream API для Rubyist
В этом посте я покажу, как решить ту же проблему с помощью API Java Stream по сравнению с использованием Ruby. Пожалуйста, ознакомьтесь с решениями, написанными на Ruby и Java, чтобы получить общее представление о Java Stream API.
Представьте проблему
Вот задача, над которой мы работаем сегодня: для каждого слова в данном предложении подсчитайте количество различных гласных и верните список подсчета.
Например, с входной строкой: «Это пример предложения.» Программа, которую мы предполагаем написать, вернет массив [1, 1, 1, 2, 1, 1]. В слове «это» всего 1 гласная, то есть яв слове «is» 1 гласная, в «a» 1 гласная, в «example» 3 гласных, а буква «e» встречается дважды, только одна из них является счетной, поэтому количество дистантных гласных в слове » пример» равен 2. Та же логика применяется к слову «предложение», потому что буква «e» встречается 3 раза и считается за 1 букву.
Разработка решения
Мне нравится идея разбивать сложные операции на несколько более мелких шагов. Давайте определим шаги, которые мы должны предпринять, чтобы вернуть выходной массив.
- Мы разбиваем массив на список слов.
- Для каждого слова мы извлекаем все гласные в список.
- Мы собираем только отдельные гласные из каждого списка гласных.
- Мы получаем размер каждого списка и сопоставляем его с конечным результатом.
С учетом примера ввода, упомянутого в предыдущем разделе, вот как он преобразовывался на каждом этапе:
Рубиновое решение
VOWELS = %w(a e o u i A E O U I)
sentence = "This is an example of sentence"
def count_vowels(sentence)
sentence
.split
.map(&:chars)
.map { |chars| vowels(chars) }
.map(&:uniq)
.map(&:size)
end
def vowels(chars)
chars.select { |char| VOWELS.include?(char) }
end
puts count_vowels(sentence).inspect
Java-решение
private Stream<String> vowels(String[] characters) {
List<String> vowels = asList("a", "i", "o", "e", "u");
return Stream.of(characters).filter(vowels::contains);
}
public List<Integer> countVowels(String sentence) {
return Arrays.stream(sentence.split(" "))
.map(word -> word.split(""))
.map(this::vowels)
.map(vowelsStream -> vowelsStream.distinct().collect(toList()))
.map(List::size)
.collect(toList());
}
Так как?
Код кажется чистым для обеих реализаций. Код говорит сам за себя, а синтаксис прост.
Код Java написан с использованием Java 8 Stream API. Это огромное улучшение в языке Java. Stream API — это функциональный способ написания кода. Это позволяет разработчику больше сосредоточиться на потоке данных, а не на деталях реализации.
Код Ruby использует Enumerable, который включен в Core Ruby. Это способ по умолчанию для обработки набора данных.
Когда я реализовал решение на Ruby и на Java, я обнаружил, что между этими двумя языками есть некоторые различия. Ruby не требует от нас разделения рабочего процесса на стадию процесса и терминальную операцию, как в Java. Есть несколько вещей, которые вы можете сделать на обоих этапах, что может запутать, какой этап является правильным.
Вы можете задаться вопросом, как прийти к такому решению, или иметь какие-либо опасения по поводу потокового API и перечисления Ruby, пожалуйста, дайте мне знать, комментируя ниже.