Перейти к основному содержимому

Списки в Groovy

· 7 мин. чтения

Задача: Сумма двух чисел

Напишите функцию twoSum. Которая получает массив целых чисел nums и целую сумму target, а возвращает индексы двух чисел, сумма которых равна target. Любой набор входных данных имеет ровно одно решение, и вы не можете использовать один и тот же элемент дважды. Ответ можно возвращать в любом порядке...

ANDROMEDA

1. Обзор

В Groovy мы можем работать со списками точно так же, как в Java . Но с поддержкой методов расширения он поставляется с гораздо большим.

В этом руководстве мы рассмотрим подход Groovy к изменению, фильтрации и сортировке списков.

2. Создание списков Groovy

Groovy предоставляет несколько интересных сокращений при работе с коллекциями, которые используют поддержку динамической типизации и буквального синтаксиса.

Давайте начнем с создания списка с некоторыми значениями, используя сокращенный синтаксис:

def list = [1,2,3]

Точно так же мы можем создать пустой список:

def emptyList = []

По умолчанию Groovy создает экземпляр java.util.ArrayList. Однако мы также можем указать тип списка для создания :

def linkedList = [1,2,3] as LinkedList
ArrayList arrList = [1,2,3]

Затем списки можно использовать для создания других списков с помощью аргумента конструктора:

def copyList = new ArrayList(arrList)

или путем клонирования:

def cloneList = arrList.clone()

Обратите внимание, что клонирование создает поверхностную копию списка.

Groovy использует оператор «==» для сравнения элементов в двух списках на равенство. Продолжая предыдущий пример, при сравнении cloneList с arrlist результат верен:

assertTrue(cloneList == arrList)

Теперь давайте посмотрим, как выполнять некоторые распространенные операции со списками.

3. Извлечение элементов из списка

Мы можем получить элемент из списка, используя буквенный синтаксис, такой как:

def list = ["Hello", "World"]
assertTrue(list[1] == "World")

или используя методы get() и getAt() :

assertTrue(list.get(1) == "World")
assertTrue(list.getAt(1) == "World")

Мы также можем получить элементы из списка, используя как положительные, так и отрицательные индексы. При использовании отрицательного индекса список читается справа налево:

assertTrue(list[-1] == "World")
assertTrue(list.getAt(-2) == "Hello")

Обратите внимание, что метод get() не поддерживает отрицательные индексы.

4. Добавление элементов в список

Существует несколько сокращенных способов добавления элементов в список. Давайте определим пустой список и добавим в него несколько элементов:

def list = []

list << 1
list.add("Apple")
assertTrue(list == [1, "Apple"])

Далее мы также можем указать индекс для размещения элемента. Кроме того, если длина списка меньше указанного индекса, то Groovy добавляет столько нулевых значений, сколько разница :

list[2] = "Box"
list[4] = true
assertTrue(list == [1, "Apple", "Box", null, true])

Наконец, мы можем использовать оператор « +=» для добавления новых элементов в список. По сравнению с другими подходами этот оператор создает новый объект списка и присваивает его переменной list :

def list2 = [1,2]
list += list2
list += 12
assertTrue(list == [1, 6.0, "Apple", "Box", null, true, 1, 2, 12])

5. Обновление элементов в списке

Мы можем обновлять элементы в списке, используя литеральный синтаксис или метод set() :

def list =[1, "Apple", 80, "App"]
list[1] = "Box"
list.set(2,90)
assertTrue(list == [1, "Box", 90, "App"])

В этом примере элементы с индексами 1 и 2 обновляются новыми значениями.

6. Удаление элементов из списка

Мы можем удалить элемент по определенному индексу, используя метод remove() :

def list = [1,2,3,4,5,5,6,6,7]
list.remove(3)
assertTrue(list == [1,2,3,5,5,6,6,7])

Или мы также можем удалить элемент, используя метод removeElement() . Это удаляет первое вхождение элемента из списка:

list.removeElement(5)
assertTrue(list == [1,2,3,5,6,6,7])

Кроме того, мы можем использовать оператор минус , чтобы удалить все вхождения элемента из списка . Однако этот оператор не изменяет базовый список — он возвращает новый список:

assertTrue(list - 6 == [1,2,3,5,7])

7. Итерация по списку

Groovy добавил новые методы в существующий API коллекций Java. Эти методы упрощают такие операции, как фильтрация, поиск, сортировка, агрегирование и т. д., путем инкапсуляции шаблонного кода. Также они поддерживают широкий спектр входных данных, включая замыкания и структуры выходных данных.

Давайте начнем с рассмотрения двух методов перебора списка.

Метод each() принимает замыкание и очень похож на метод foreach () в Java. Groovy передает неявный параметр , который соответствует текущему элементу на каждой итерации:

def list = [1,"App",3,4]
list.each {println it * 2}

Другой метод, eachWithIndex() , предоставляет текущее значение индекса в дополнение к текущему элементу:

list.eachWithIndex{ it, i -> println "$i : $it" }

8. Фильтрация

Фильтрация — еще одна операция, часто выполняемая со списками, и Groovy предоставляет на выбор множество различных методов.

Давайте определим список для работы:

def filterList = [2,1,3,4,5,6,76]

Чтобы найти первый объект, соответствующий условию, мы можем использовать find :

assertTrue(filterList.find {it > 3} == 4)

Чтобы найти все объекты, соответствующие условию, мы можем использовать findAll :

assertTrue(filterList.findAll {it > 3} == [4,5,6,76])

Давайте посмотрим на другой пример. Здесь нам нужен список всех элементов, которые являются числами:

assertTrue(filterList.findAll {it instanceof Number} == [2,1,3,4,5,6,76])

Кроме того, мы можем использовать метод grep , чтобы сделать то же самое:

assertTrue(filterList.grep( Number ) == [2,1,3,4,5,6,76])

Разница между методами grep и find заключается в том, что grep может принимать объект или замыкание в качестве аргумента. Таким образом, это позволяет еще больше сократить оператор условия до минимума:

assertTrue(filterList.grep {it > 6} == [76])

Кроме того, grep использует Object#isCase(java.lang.Object) для оценки условия для каждого элемента списка.

Иногда нас могут интересовать только уникальные элементы списка . Есть два перегруженных метода, которые мы можем использовать для этой цели.

Метод unique() необязательно принимает замыкание и сохраняет в базовом списке только те элементы, которые соответствуют условиям замыкания, отбрасывая другие. Он использует естественный порядок по умолчанию для определения уникальности:

def uniqueList = [1,3,3,4]
uniqueList.unique()
assertTrue(uniqueList == [1,3,4])

В качестве альтернативы, если требуется не изменять базовый список, мы можем использовать метод toUnique() :

assertTrue(["A", "B", "Ba", "Bat", "Cat"].toUnique {it.size()} == ["A", "Ba", "Bat"])

Если мы хотим проверить, что некоторые или все элементы в списке удовлетворяют определенному условию, мы можем использовать методы Every() и Any() .

Метод Every() оценивает условие в замыкании для каждого элемента в списке. Затем он возвращает true только в том случае, если все элементы в списке удовлетворяют условию:

def conditionList = [2,1,3,4,5,6,76]
assertFalse(conditionList.every {it < 6})

С другой стороны, метод any() возвращает true , если какой-либо элемент в списке удовлетворяет условию:

assertTrue(conditionList.any {it % 2 == 0})

9. Сортировка

По умолчанию Groovy сортирует элементы в списке в соответствии с их естественным порядком:

assertTrue([1,2,1,0].sort() == [0,1,1,2])

Но мы также можем передать компаратор с пользовательской логикой сортировки :

Comparator mc = {a,b -> a == b? 0: a < b? 1 : -1}
def list = [1,2,1,0]
list.sort(mc)
assertTrue(list == [2,1,1,0])

Кроме того, мы можем использовать методы min() или max() , чтобы найти максимальное или минимальное значение без явного вызова sort():

def strList = ["na", "ppp", "as"]
assertTrue(strList.max() == "ppp")
Comparator minc = {a,b -> a == b? 0: a < b? -1 : 1}
def numberList = [3, 2, 0, 7]
assertTrue(numberList.min(minc) == 0)

10. Коллекционирование

Иногда нам может понадобиться изменить элементы в списке и вернуть другой список с обновленными значениями. Это можно сделать с помощью метода collect() :

def list = ["Kay","Henry","Justin","Tom"]
assertTrue(list.collect{"Hi " + it} == ["Hi Kay","Hi Henry","Hi Justin","Hi Tom"])

11. Присоединение

Иногда нам может понадобиться объединить элементы в список. Для этого мы можем использовать метод join() :

assertTrue(["One","Two","Three"].join(",") == "One,Two,Three")

12. Заключение

В этой статье мы рассмотрели несколько расширений, которые Groovy добавляет в API коллекций Java.

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

Наконец, мы рассмотрели поддержку Groovy для итерации, фильтрации, поиска, сбора, объединения и сортировки списков.

Как всегда, все примеры, обсуждаемые в статье, доступны на GitHub .