Ответ Эрана описал различия между версиями reduce
с двумя аргументами и тремя аргументами в том, что первая уменьшает Stream
до T
, тогда как последняя уменьшает Stream
до U
. Тем не менее, на самом деле он не объяснил необходимость дополнительной функции объединителя при уменьшении Stream
до U
.
. Один из принципов проектирования API Streams заключается в том, что API не должен отличаться последовательным и параллельным потокам или другим способом, конкретный API не должен препятствовать правильной работе потока последовательно или параллельно. Если ваши лямбды имеют правильные свойства (ассоциативные, неинтерферирующие и т. Д.), Поток, выполняемый последовательно или параллельно, должен давать одинаковые результаты.
Давайте сначала рассмотрим версию сокращения с двумя аргументами:
T reduce(I, (T, T) -> T)
Последовательная реализация проста. Значение идентичности I
«накапливается» с элементом нулевого потока, чтобы дать результат. Этот результат накапливается с первым элементом потока, чтобы дать другой результат, который, в свою очередь, накапливается со вторым элементом потока и т. Д. После того, как последний элемент накоплен, возвращается окончательный результат.
Параллельная реализация начинается с разделения потока на сегменты. Каждый сегмент обрабатывается собственным потоком последовательным образом, описанным выше. Теперь, если у нас есть N потоков, мы имеем N промежуточных результатов. Их необходимо сократить до одного результата. Поскольку каждый промежуточный результат имеет тип T, и у нас есть несколько, мы можем использовать одну и ту же функцию аккумулятора, чтобы уменьшить эти промежуточные результаты до одного результата.
Теперь рассмотрим гипотетическую операцию сокращения двух аргументов что уменьшает Stream
до U
. В других языках это называется операцией «fold» или «fold-left», поэтому я назову ее здесь. Обратите внимание, что это не существует в Java.
U foldLeft(I, (U, T) -> U)
(Обратите внимание, что значение идентификатора I
имеет тип U.)
Последовательная версия foldLeft
как последовательная версия reduce
, за исключением того, что промежуточные значения имеют тип U вместо типа T. Но в остальном это одно и то же. (Гипотетическая операция foldRight
будет аналогичной, за исключением того, что операции будут выполняться справа налево, а не слева направо.)
Теперь рассмотрим параллельную версию foldLeft
. Начнем с разделения потока на сегменты. Затем мы можем иметь, что каждый из N потоков уменьшает значения T в своем сегменте на N промежуточных значений типа U. Теперь что? Как мы получаем от N значений типа U до одного результата типа U?
Отсутствует другая функция, которая объединяет несколько промежуточных результатов типа U в один результат типа U. Если мы имеют функцию, которая объединяет два значения U в один, это достаточно, чтобы уменьшить любое количество значений до одного - так же, как и исходное сокращение выше. Таким образом, операция сокращения, которая дает результат другого типа, нуждается в двух функциях:
U reduce(I, (U, T) -> U, (U, U) -> U)
Или, используя синтаксис Java:
U reduce(U identity, BiFunction accumulator, BinaryOperator combiner)
Итак, чтобы сделать параллельное сокращение к другому типу результата, нам нужны две функции: одна, которая накапливает элементы Т до промежуточных значений U, и вторую, которая объединяет промежуточные значения U в единый результат U. Если мы не переключаем типы, получается, что функция аккумулятора такая же, как функция объединителя. Вот почему сокращение до одного и того же типа имеет только функцию аккумулятора, а уменьшение к другому типу требует отдельных функций аккумулятора и объединителя.
Наконец, Java не предоставляет операции foldLeft
и foldRight
, потому что они подразумевают конкретный порядок операций, который по своей сути является последовательным. Это противоречит описанному выше принципу проектирования предоставления API, которые поддерживают последовательную и параллельную работу в равной степени.
Попробуйте
re.search(r'\bis\b', your_string)
Из docs :
\ b Соответствует пустой строке, но только в начале или конце слово.
Обратите внимание, что модуль
re
использует наивное определение «слова» как «последовательность буквенно-цифровых символов или символов подчеркивания», где «буквенно-цифровое» зависит от параметров локали или юникода.Также обратите внимание, что без префикса исходной строки
\b
рассматривается как «обратное пространство» вместо границы слова регулярного выражения.
Попробуйте это с использованием границы слова в регулярном выражении:
>>> x="this is a sample"
>>> y="this isis a sample."
>>> regex=re.compile(r"\bis\b") # For ignore case: re.compile(r"\bis\b", re.IGNORECASE)
>>> regex.findall(y)
[]
>>> regex.findall(x)
['is']
Из документации re.search()
.
It matches the empty string, but only at the beginning or end of a word
E.g. r'\bfoo\b' matches 'foo', 'foo.', '(foo)', 'bar foo baz' but not 'foobar' or 'foo3'
Надеюсь, что это поможет!
Проблема с регулярным выражением состоит в том, что если строка hte, которую вы хотите найти в другой строке, имеет символы регулярных выражений, она становится сложной. любая строка с скобками не сработает.
Этот код найдет слово
word="is"
srchedStr="this is a sample"
if srchedStr.find(" "+word+" ") >=0 or \
srchedStr.endswith(" "+word):
<do stuff>
Первая часть условного поиска текста с пространством с каждой стороны и второй частью улавливает конец строковой ситуации. Обратите внимание, что endwith является логическим, тогда как find
возвращает целое число
test!
не является словом, каким-либо определением, которое я знаю. Интересно, что он работает для сокращений:re.search(r"\bisn't\b", "it isn't bad")
возвращает совпадение. – Jeff Learman 14 June 2018 в 17:16