Статьи

Скала: Коллекции 1

Этот пост содержит некоторую информацию о коллекциях Scala.

Проблема?

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

Шаг 1: Представление игрока в регби.

Итак, очевидно, что мы хотим, чтобы что-то вроде POJO представляло игрока в регби. Этот

Представление должно содержать имя игрока, его команду и время, когда они могут пройти 100 метров. Давайте использовать конструкцию класса случая Scala

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

1
case class RugbyPlayerCaseClass(team: String, sprintTime100M: BigDecimal, name: String)

Шаг 2: Создайте игроков в регби

1
2
3
4
5
val lukeFitzGerald = RugbyPlayerCaseClass('Leinster', 10.2, 'Luke Fitzgerald');
val fergusMcFadden = RugbyPlayerCaseClass('Leinster', 10.1, 'Fergus McFadden');
val rog = RugbyPlayerCaseClass('Leinster', 12, 'Ronan O'Gara');
val tommyBowe = RugbyPlayerCaseClass('Ulster', 10.3, 'Tommy Bowe');
val leoCullen = RugbyPlayerCaseClass('Leinster', 15, 'Leo Cullen');

Код выше должен быть понятен. Различные игроки в регби создаются. Обратите внимание на вывод текста. Нет необходимости объявлять игроков в регби типами RugbyPlayers. Вместо этого это выводится. Еще одна интересная вещь — это ключевое слово val . Это означает, что ссылка неизменна. Это эквивалент final в Java.

Шаг 3: Напишите функцию

1
2
def validByAge(in: List[RugbyPlayerCaseClass]) =
     in.filter(_.team == 'Leinster').sortWith(_.sprintTime100M < _.sprintTime100M).map(_.name);

Ключевые моменты относительно этой функции:

  • Функция начинается с ключевого слова def обозначающего объявление функции.
  • Список экземпляров RugbyPlayerCaseClass принимается в качестве входных данных. Тип List является типом Scala.
  • Тип возврата не является обязательным. В этом случае он не указан явно, так как выводится.
  • Часть слева от = — это то, что делает функция. В этом случае функция вызывает три оператора сбора разностей.
    • .filter(_.team =='Leinster) — выполняет итерацию по каждому элементу в списке. На каждой итерации _ заполняется текущим значением в списке. Если свойство команды текущего игрока в регби — Leinster, элемент включается в результирующую коллекцию.
    • .sortWith(_.sprintTime100M < _.sprintTime100M) — sortWith — это специальный метод, который мы можем использовать для сортировки коллекций. В этом случае мы сортируем выходные данные из предыдущего оператора коллекции и сортируем на основе sprintTime для 100M.
    • .map(_.name) — это сопоставляет каждый элемент из вывода оператора сортировки только с именем свойства.
  • Тело функции не обязательно должно быть заключено в {}, потому что это только один строчный код.
  • Нет необходимости в возврате. В Scala все, что оценивает последняя строка, будет возвращено. В этом примере, поскольку есть только одна строка, последняя строка является первой строкой.

Напоследок — собери все вместе.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
object RugbyPlayerCollectionDemos {
  def main(args: Array[String]){
    println('Scala collections stuff!');
    showSomeFilterTricks();
  }
 
  // Case class remove need for boiler plater code.
  case class RugbyPlayerCaseClass(team: String, sprintTime100M: BigDecimal, name: String)
 
  def showSomeFilterTricks() {
 
    // team: String, sprintTime100M: Int, name: String
    val lukeFitzGerald = RugbyPlayerCaseClass('Leinster', 10.2, 'Luke Fitzgerald');
    val fergusMcFadden = RugbyPlayerCaseClass('Leinster', 10.1, 'Fergus McFadden');
    val rog = RugbyPlayerCaseClass('Munster', 12, 'Ronan O'Gara');
    val tommyBowe = RugbyPlayerCaseClass('Ulster', 10.3, 'Tommy Bowe');
    val leoCullen = RugbyPlayerCaseClass('Leinster', 15, 'Leo Cullen');
 
    println(validByAge(List(lukeFitzGerald, fergusMcFadden, rog, tommyBowe, leoCullen)));
 
  }
 
  def validByAge(in: List[RugbyPlayerCaseClass]) =
     in.filter(_.team == 'Leinster').sortWith(_.sprintTime100M < _.sprintTime100M).map(_.name);
 
}

Вышеприведенная программа выведет:

1
2
Scala collections stuff!
List(Luke Fitzgerald, Fergus McFadden, Leo Cullen)

Нечто подобное в Java Pre Java 8, для реализации той же функциональности в Java было бы гораздо больше кода.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
public class RugbyPLayerCollectionDemos {
    public static void main(String args[]) {
     RugbyPLayerCollectionDemos collectionDemos = new RugbyPLayerCollectionDemos();
     collectionDemos.showSomeFilterTricks();
    }
 
    public void showSomeFilterTricks() {
        // team: String, sprintTime100M: Int, name: String
        final RugbyPlayerPOJO lukeFitzGerald = new RugbyPlayerPOJO('Leinster', new BigDecimal(10.2), 'Luke Fitzgerald');
        final RugbyPlayerPOJO fergusMcFadden = new RugbyPlayerPOJO('Leinster', new BigDecimal(10.1), 'Fergus McFadden');
        final RugbyPlayerPOJO rog = new RugbyPlayerPOJO('Munster', new BigDecimal(12), 'Ronan O'Gara');
        final RugbyPlayerPOJO tommyBowe = new RugbyPlayerPOJO('Ulster', new BigDecimal(10.3), 'Tommy Bowe');
        final RugbyPlayerPOJO leoCullen = new RugbyPlayerPOJO('Leinster', new BigDecimal(15), 'Leo Cullen');
 
        List
 
                       rugbyPlayers = Arrays.asList(lukeFitzGerald,
          fergusMcFadden, rog, tommyBowe, leoCullen);
 
        System.out.println(filterRugbyPlayers(rugbyPlayers));
    }
 
    /**
     * Return the names of Leinster Rugby players in the order of their sprint times.
     */
    public List
 
                        filterRugbyPlayers(List
 
                         pojos) {
        ArrayList
 
                          leinsterRugbyPlayers = new    ArrayList
 
                          ();
 
        for (RugbyPlayerPOJO pojo: pojos) {
            if (pojo.getTeam().equals('Leinster')) {
               leinsterRugbyPlayers.add(pojo);
            }
        }
 
        RugbyPlayerPOJO [] rugbyPlayersAsArray = leinsterRugbyPlayers.toArray(new   RugbyPlayerPOJO[0]);
 
        Arrays.sort(rugbyPlayersAsArray, new Comparator
 
                           () {
            public int compare(RugbyPlayerPOJO rugbyPlayer1, RugbyPlayerPOJO rugbyPlayer2) {
                 return rugbyPlayer1.getSprintTime100M().compareTo(rugbyPlayer2.getSprintTime100M());
           }
        }); 
 
        List
 
                             rugbyPlayersNamesToReturn = new ArrayList
 
                             ();
 
        for (RugbyPlayerPOJO rugbyPlayerPOJO: rugbyPlayersAsArray) {
             rugbyPlayersNamesToReturn.add(rugbyPlayerPOJO.getName());
        }
 
        return rugbyPlayersNamesToReturn;
    }
 
    class RugbyPlayerPOJO {
        private BigDecimal sprintTime100M;
        private String team;
        private String name;
 
        public RugbyPlayerPOJO(String team, java.math.BigDecimal sprintTime100M, String name) {
            this.name = name;
            this.sprintTime100M = sprintTime100M;
            this.team = team;
        }
 
        public BigDecimal getSprintTime100M() {
            return sprintTime100M;
        }
 
        public String getTeam() {
            return team;
        }
 
        public String getName() {
            return name;
        }
    }
}

Выручает ли Java 8?

Да. Согласно спецификациям проекта Lambda, Java 8 будет иметь похожие функции фильтра, отображения и сортировки . Функциональность этого поста в Java 8 будет выглядеть примерно так:

01
02
03
04
05
06
07
08
09
10
List
 
                       rugbyPlayers = Arrays.asList(lukeFitzGerald,
  fergusMcFadden, rog, tommyBowe, leoCullen);
//...
//...
List
 
                        filteredPLayersNames = rugbyPlayers.filter(e -> e.getTeam.equals('Leinster')).
 sorted((a, b) -> a.getSprintTime100M() - b.getSprintTime100M()).mapped(e -> {return e.getName();}).into(new List<>());

Так что Java 8 определенно догоняет многое в этом отношении. Но будет ли этого достаточно?

Ссылка: Scala: Коллекции 1 от нашего партнера JCG Алекса Стейвли в блоге Techlin в Дублине .