Имейте в виду, что map.max(Closure cl)
возвращает Map.Entry<String, Integer>
, а не карту.Поэтому, если вы ожидаете карту с одним ключом, вам придется создать ее из полученного вами результата.
Map.max(Closure cl)
ищет максимальное значение и возвращает его.Не существует варианта, позволяющего изменить поведение функции в случае двух записей, содержащих максимальное значение.Согласно документации:
Выбирает запись на карте, имеющую максимальное вычисленное значение, определяемое поставляемым замыканием.Если более одной записи имеет максимальное значение, между записями, имеющими максимальное значение, делается произвольный выбор.
На практике: возвращается первая найденная запись с максимальным значением.
Groovy, однако, предлагает другую функцию сбора, которую можно использовать для достижения ожидаемого результата - Collection.inject(initialValue, closure)
.Это эквивалент популярной функции fold
, хорошо известной в парадигме функционального программирования.Он начинается с некоторого начального значения, выполняет итерацию коллекции и применяет функцию к каждому элементу (эта функция возвращает новое значение, которое заменяет значение, переданное в качестве начального значения), чтобы сократить список элементов до одного элемента за одну итерацию.Collection.inject()
javadoc дает очень наглядный пример суммирования всех чисел из списка:
assert 0+1+2+3+4 == [1,2,3,4].inject(0) { acc, val -> acc + val }
Теперь давайте посмотрим, как мы можем использовать эту функцию для достижения ожидаемого результата.Рассмотрим следующий пример:
def map2= ['a': 3, 'b': 4, 'c':4]
Tuple2<String, Integer> result = map2.inject(new Tuple2<String, Integer>(null, null)) { Tuple2<String, Integer> tuple, entry ->
entry.value >= tuple.second ?
new Tuple2<>(entry.value == tuple.second ? '+1than1' : entry.key, entry.value) :
tuple
}
assert result.first == '+1than1'
assert result.second == 4
Здесь мы начнем с new Tuple2<String, Integer>(null, null)
в качестве начального значения - a Tuple2
представляет пару из двух значений.В нашем случае это ключ и максимальное значение.Закрытие проверяет, является ли текущее значение записи больше или равно значению, которое мы храним в кортеже, и если это правда, оно проверяет, совпадает ли значение с тем, которое мы уже нашли - если это правда, оно использует +than1
в качествеключ вместо ключа, взятого из карты.В противном случае он просто использует ключ ввода без каких-либо изменений.Когда значение ниже, чем то, которое мы сейчас храним в кортеже, возвращается существующий кортеж.И, наконец, мы получаем кортеж, в котором tuple.first
содержит ключ, а tuple.second
содержит максимальное значение.
Конечно, чтобы сделать inject
часть более читабельной, стоит извлечь класс данных, который представляет вашожидаемый результат и поведение.Вы можете реализовать такую функцию, как compareAndReplace
, чтобы определить конкретное поведение при обнаружении другого максимального значения.Примерно так:
import groovy.transform.Immutable
@Immutable
class Result {
static Result EMPTY = new Result(null, null)
String key
Integer value
Result compareAndReplace(Map.Entry<String, Integer> entry, String key = '+1than1') {
entry.value >= value ?
new Result(entry.value == value ? key : entry.key, entry.value) :
this
}
}
def map2 = ['a': 3, 'b': 4, 'c': 4]
Result result = map2.inject(Result.EMPTY) { Result result, entry -> result.compareAndReplace(entry) }
assert result.key == '+1than1'
assert result.value == 4