изменить ключ карты, когда имеется более одного значения maximun для нестандартного clousure - PullRequest
0 голосов
/ 14 октября 2018

У меня есть две карты:

def map = ['a': 3, 'b': 4, 'c':5]
def map2= ['a': 3, 'b': 4, 'c':4]

Я хочу взять максимальное значение карты следующим образом:

def newMap = map.max {it.value}

и мой вывод правильный ('c': 5), моя проблема со второй картой, потому что существует более одного максимального значения.В этом случае я хочу, чтобы изменил ключ , чтобы я мог знать, что было более одного максимального значения.Я хочу, чтобы мой вывод был:

def newMap2 = map2.max {it.value}
assert newMap2 == ['+than1': 4]

Могу ли я изменить ключ карты в этом конкретном случае, используя функции groovy?Могу ли я добиться этого внутри максимального закрытия?

Я не хочу менять ключ, если не более одного максимального значения.

Ответы [ 2 ]

0 голосов
/ 15 октября 2018

Вы можете сделать это в однострочнике, но это все еще немного неясно:

println map2.groupBy{ it.value }.max{ it.key }.value.with{ it.size() > 1 ? ['+than1': it.values()[0]] : it }

Я бы, по крайней мере, извлек бы последнее Закрытие:

def mergedKey = { it.size() > 1 ? ['+than1': it.values()[0]] : it }
def newMap2 = map2.groupBy{ it.value }.max{ it.key }.value.with(mergedKey)
assert newMap2 == ['+than1': 4]
0 голосов
/ 14 октября 2018

Имейте в виду, что 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...