Коллекции представляют собой Java классы, предназначенные для эффективного хранения нескольких элементов определенных типов. В отличие от массивов Java, коллекции могут содержать любое число элементов.
Список ArrayList (объект) — это простейшая коллекция в AnyLogic, которую можно рассматривать как изменяемый массив.
Следующая строка кода создает изначально пустой список ArrayList объектов класса Person:
ArrayList<Person> friends = new ArrayList<Person>();
Обратите внимание, что тип коллекции содержит тип элемента, заключенный в угловые скобки. Таким образом коллекция «настраивается» для работы с определенным типом элементов, вследствие чего, например, функция get() объекта friends вернет объект типа Person.
ArrayList предоставляет перечисленные ниже функции. Полное описание API приведено в справочнике классов AnyLogic.
Функция | Описание |
---|---|
int size() | Возвращает количество элементов в списке. |
boolean isEmpty() | Проверяет данный список на отсутствие элементов. |
Person get(int index) |
Возвращает элемент, находящийся на указанной позиции в списке. index — Позиция, с которой нужно извлечь элемент. |
boolean add(Person p) |
Добавляет указанный элемент в конец списка. p — Элемент, который необходимо добавить. |
Person remove(int index) |
Удаляет элемент, находящийся на указанной позиции в списке. index — Позиция, из которой необходимо удалить элемент. |
boolean contains(Person p) |
Возвращает true, если данный элемент содержится в списке. p — Элемент, на наличие которого проводится проверка. |
void clear() | Удаляет все элементы из списка. |
-
Следующий фрагмент кода проверяет, содержит ли список friends элемент victor, и если нет, то добавляет его в список:
if( ! friends.contains( victor ) ) friends.add( victor );
-
Все типы коллекций поддерживают итерирование по элементам. Самой простой конструкцией для итерации является цикл for.
Предположим, что у класса Person есть поле income. Приведенный ниже цикл распечатывает всех друзей с доходами больше 100000 в лог модели:or( Person p : friends ) { if( p.income > 100000 ) traceln( p ); }
Связный список (объект LinkedList) — еще один популярный тип коллекции.
Рассмотрим модель, в которой дистрибьютор хранит журнал невыполненных заказов, полученных от ритейлеров. Предположим, есть класс Order с полем amount. Тогда журнал (являющийся, по сути, очередью FIFO: “первым пришёл — первым обслужен”) может быть промоделирован так:
LinkedList<Order> backlog = new LinkedList<Order>();
Класс LinkedList поддерживает общие для всех коллекций функции (такие как size() или isEmpty()), а также предлагает дополнительный набор методов.
Функция | Описание |
---|---|
Order getFirst() | Возвращает первый элемент списка. |
Order getLast() | Возвращает последний элемент списка. |
addFirst(Order o) |
Вставляет заданный элемент в начало списка. o — Элемент, который необходимо вставить. |
addLast(Order o) |
Добавляет заданный элемент в конец списка. o — Элемент, который необходимо добавить. |
Order removeFirst() | Возвращает первый элемент списка и удаляет его. |
Order removeLast() | Возвращает последний элемент списка и удаляет его. |
Когда дистрибьютор получает новый заказ, он помещает его в конец списка невыполненных заказов:
backlog.addLast(order);
Каждый раз, когда запасы товаров пополняются, дистрибьютор пытается отправить товары согласно заказу, находящемуся в начале журнала. Если значение в заказе превышает имеющиеся в наличии товары, то обработка заказа прекращается. Обработка может выглядеть так:
while(!backlog.isEmpty()) { // повторяем код ниже, пока журнал не пуст
Order order = backlog.getFirst(); // берем первый заказ из журнала
if(order.amount <= inventory) { // если достаточно товара, чтобы выполнить заказ
ship(order); // выполняем заказ
inventory -= order.amount; // уменьшаем количество товара на складе
backlog.removeFirst(); // удаляем заказ из журнала
} else { // если недостаточно товара,
break; // прекращаем обработку журнала заказов
}
}
Мы советуем задавать коллекции в агентах и экспериментах графически. Элемент Коллекция расположен в Основной палитре. Всё, что вам нужно сделать — это перетащить его из палитры на диаграмму и выбрать тип коллекции и тип элементов. Во время выполнения модели вы сможете просмотреть содержимое коллекции, щелкнув по её значку.
Различные типы коллекций имеют разную временную сложность операций. Например, проверка наличия заданного объекта в коллекции, содержащей 10 000 000 объектов, может потребовать 80 миллисекунд для коллекции типа ArrayList, 100 миллисекунд — для LinkedList, и менее 1 миллисекунды — для HashSet и TreeSet. Для обеспечения наибольшей эффективности необходимо исследовать, какие из операций наиболее часто выполняются, и выбрать соответствующий тип коллекции. В следующей таблице приведена временная сложность наиболее часто используемых операций для четырех типов коллекций.
Операция | ArrayList | LinkedList | HashSet | TreeSet |
---|---|---|---|---|
Получение размера | Постоянная | Постоянная | Постоянная | Постоянная |
Добавление элемента | Постоянная | Постоянная | Постоянная | Логарифмическая |
Удаление данного элемента | Линейная | Линейная | Постоянная | Логарифмическая |
Удаление по индексу | Линейная | Линейная | - | - |
Получение элемента по индексу | Постоянная | Линейная | - | - |
Определение присутствия элемента в коллекции | Линейная | Линейная | Постоянная | Логарифмическая |
Термины постоянная, линейная и логарифмическая сложность означают следующее:
- Линейная сложность означает, что наихудшее время, необходимое для выполнения операции, растет линейно с увеличением размера коллекции.
- Постоянная сложность означает, что время выполнения операции вообще не зависит от размера коллекции.
- Логарифмическая сложность означает, что время выполнения операции растет параллельно логарифму ее размера.
Обратите внимание на приведенный ниже рисунок. Вполне может быть, что при относительно малом числе элементов коллекция с линейной сложностью будет работать лучше, чем коллекция с постоянной сложностью.
И пара моментов, которые следует знать при выборе типа коллекции:
- HashSet и TreeSet не поддерживают индексацию элементов, поэтому нельзя, например, получить элемент из позиции с индексом 32.
- TreeSet представляет собой коллекцию, сортируемую естественным образом, элементы располагаются в определенном порядке, определяемым исходным или заданном пользователем компаратором.
Когда вы создаете популяцию агентов, AnyLogic создает специальный тип коллекции для хранения отдельных агентов. Вы можете выбрать один из двух следующих типов:
- AgentArrayList — Выберите этот тип коллекции, если набор агентов более или менее постоянен, или если необходимо часто обращаться к отдельным агентам по индексу.
- AgentLinkedHashSet — Выберите этот тип коллекции, если вы планируете часто добавлять новых агентов и удалять существующих. Например, если вы моделируете население города в течение относительно длительного периода времени, так что люди рождаются, умирают, уезжают из города, а новые люди прибывают.
Тип коллекции можно выбрать в секции свойств Специфические вложенного агента: см. рисунок ниже.
Обе коллекции агентов поддерживают функции size(), isEmpty(), get(int index), contains(Object o) и итерацию по элементам. Если во время итерации не нужно оперировать со значением текущего индекса, то всегда лучше использовать упрощенную форму цикла for:
for(Person p : people) {
…
}
-
Как мы можем улучшить эту статью?
-