
edu.uvm.ccts.arden.model.AList Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of arden-model Show documentation
Show all versions of arden-model Show documentation
The Java model used to represent Arden objects
/*
* Copyright 2015 The University of Vermont and State
* Agricultural College, Vermont Oxford Network, and The University
* of Vermont Medical Center. All rights reserved.
*
* Written by Matthew B. Storer
*
* This file is part of Arden Model.
*
* Arden Model is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Arden Model is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Arden Model. If not, see .
*/
package edu.uvm.ccts.arden.model;
import edu.uvm.ccts.arden.util.ListUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import java.util.*;
/**
* An Arden List object
*
* A list is an ordered set of elements, each of which may be null, Boolean, event, destination, message, term, number,
* time, duration, or string. There are no nested lists; that is, a list cannot be the element of another list. Lists
* may be heterogeneous; that is, the elements in a list may be of different types. There is one list constant, the
* empty list, which is signified by using a pair of empty parentheses: (). White space is allowed within an empty
* list's parentheses. Other lists are created by using list operators like the comma (,) to build lists from single
* items (see Section 9.2). For the output format of lists (including single element lists), see Section 9.8. For
* example, these are valid lists:
*
* - 4, 3, 5
* - 3, true, 5, null
* - ,1
* - ()
*
* If operators that expect list arguments are presented non-list arguments, the arguments are implicitly converted to
* single-element lists before the operator is applied.
* @see 8.8
*/
public class AList extends ADataType implements Iterable, RowIterable {
private List list = new ArrayList();
/**
* Construct a new, empty Arden list.
*/
public AList() {
}
/**
* Construct a new copy of an Arden list. The resulting list is a deep-copy of {@code list}. Primary times
* of list items are preserved.
* @param list
*/
public AList(AList list) {
for (ADataType item : list.list) {
this.list.add(item.copy());
}
}
public AList(List list) {
this.list = list;
}
/**
* Generates a deep-copy of this object
* @return A deep-copy of this object. Primary times are preserved.
*/
@Override
public AList copy() {
return new AList(this);
}
@Override
public String toString() {
return "(" + StringUtils.join(list, ", ") + ")";
}
/**
* @return the number of elements in the list
*/
public int size() {
return list.size();
}
/**
* Determines whether or not the list is empty
* @return true
if the list is empty; false
otherwise
*/
public boolean isEmpty() {
return list.isEmpty();
}
public boolean contains(ADataType obj) {
return list.contains(obj);
}
/**
* Gets an item from the list by index. IMPORTANT NOTE: indexes are 1-based!
* @param index
* @return
*/
public ADataType get(int index) {
if (index >= 1 && index <= list.size()) {
return list.get(index - 1);
} else {
return new ANull();
}
}
/**
* Sets an item in the list by index. IMPORTANT NOTE: indexes are 1-based!
* @param index
* @param obj
*/
public void set(int index, ADataType obj) {
if (index >= 1 && index <= list.size()) {
if (obj == null) {
list.set(index - 1, new ANull());
} else if (obj instanceof AList) {
remove(index);
insert(obj, index);
} else {
list.set(index - 1, obj);
}
}
}
@Override
public boolean hasPrimaryTime() {
return getPrimaryTime() != null;
}
/**
* Gets the primary time.
*
* This function operates by iterating through all elements in the list. This function will return a
* primary time only if all elements have the same primary time.
*
* @return a {@link Time} object representing the primary time held by all list
* elements; otherwise {@code null} is returned.
*/
@Override
public Time getPrimaryTime() {
return ListUtil.getPrimaryTime(list);
}
/**
* Add a single Arden-object into this list
* @param obj
*/
public void add(ADataType obj) {
if (obj == null) {
list.add(new ANull());
} else if (obj instanceof AList) { // nested lists are not permitted
list.addAll(((AList) obj).list);
} else {
list.add(obj);
}
}
/**
* Adds all elements from list
into this object's backing list
* @param list
*/
public void addAll(AList list) {
this.list.addAll(list.list);
}
/**
* Inserts an object into the list at the specified position. Note that unlike Java, list indexes in Arden start
* at 1, not 0.
* @param obj an object to insert into the list. If {@code obj} is an {@link AList} itself, the contents of
* {@code obj} are added to the list, starting at the specified position {@code pos}.
* @param pos the position in the list at which to insert {@code obj}. Must be a number between 1 and
* {@link #size}.
*/
public void insert(ADataType obj, int pos) {
int index;
if (pos <= 1) index = 0;
else if (pos > list.size()) index = list.size();
else index = pos - 1;
if (obj == null) {
list.add(index, new ANull());
} else if (obj instanceof AList) { // nested lists are not permitted
list.addAll(index, ((AList) obj).list);
} else {
list.add(index, obj);
}
}
/**
* Removes an item from the given position in the list. Note that unlike Java, list indexes in Arden start at 1,
* not 0.
* @param pos A number between 1 and {@link #size}
*/
public void remove(int pos) {
if (pos >= 1 && pos <= list.size()) {
list.remove(pos - 1);
}
}
/**
* @return the first element in the list, or {@link ANull} if the list is empty.
*/
public ADataType first() {
if (list.size() > 0) {
return list.get(0);
} else {
return new ANull();
}
}
/**
* @param x The number of elements from the start of the list to return
* @return the first {@code x} elements from the list, or an empty {@link AList} if the list is empty
*/
public AList first(int x) {
// todo : ensure results are earliest in time if list is the result of a time-sorted query. see 9.14.4
return sublist(1, x);
}
/**
* @return the last element in the list, or {@link ANull} if the list is empty.
*/
public ADataType last() {
if (list.size() > 0) {
return list.get(list.size() - 1);
} else {
return new ANull();
}
}
/**
* @param x The number of elements from the end of the list to return
* @return the last {@code x} elements from the list, or an empty {@link AList} if the list is empty
*/
public AList last(int x) {
// todo : ensure results are latest in time if list is the result of a time-sorted query. see 9.14.5
return sublist(list.size() - x + 1, x);
}
/**
* Returns the item from the list that has a primary time closest to the time specified. If the list contains
* any items not having a primary time, or if the list is empty, {@code null} is returned.
* @see 9.13.2
* @param time
* @return
*/
public ADataType nearest(Time time) {
if ( ! eachHasPrimaryTime() ) return null;
Long minDiff = null;
ADataType rval = null;
for (ADataType obj : list) {
long diff = Math.abs(time.subtract(obj.getPrimaryTime()).getSeconds());
if (minDiff == null || diff < minDiff) {
minDiff = diff;
rval = obj; // primary time should be maintained
}
}
return rval;
}
public ANumber nearestIndex(Time time) {
return indexOf(nearest(time)); // do not maintain primary
}
public ANumber earliestIndex() {
AList list = earliest(1);
if (list == null) return null;
else if (list.isEmpty()) return null; // if list is empty, null is returned - see 9.12.22.2
else {
ADataType obj = list.get(1);
ANumber index = indexOf(obj);
index.setPrimaryTime(obj.getPrimaryTime()); // primary time of the argument is maintained
return index;
}
}
public AList earliestIndex(int x) {
AList list = earliest(x);
if (list == null) return null;
else if (list.isEmpty()) return list;
else return indexOf(list); // do not maintain primary time
}
public ADataType earliest() {
// todo : If there is a tie, then it selects the element with the lowest index. spec 9.12.17
AList list = earliest(1);
if (list == null) return null;
else if (list.isEmpty()) return null; // return null if list is empty - see 9.12.17
else return list.get(1);
}
public AList earliest(int x) {
AList sorted = sortByTime();
if (sorted == null) return null;
AList subList = sorted.sublist(1, x);
AList list = new AList();
for (ADataType obj : this.list) {
if (subList.contains(obj)) list.add(obj); // relies on equals(), which incorporates primaryTime
}
return list;
}
public ANumber latestIndex() {
AList list = latest(1);
if (list == null) return null;
else if (list.isEmpty()) return null; // if list is empty, null is returned - see 9.12.22.1
else {
ADataType obj = list.get(1);
ANumber index = indexOf(obj);
index.setPrimaryTime(obj.getPrimaryTime()); // primary time of the argument is maintained
return index;
}
}
public AList latestIndex(int x) {
AList list = latest(x);
if (list == null) return null;
else if (list.isEmpty()) return list;
else return indexOf(list); // do not maintain primary time
}
public ADataType latest() {
// todo : If there is a tie, then it selects the element with the lowest index. spec 9.12.16
AList list = latest(1);
if (list == null) return null;
else if (list.isEmpty()) return null; // return null if list is empty - see 9.12.16
else return list.get(1);
}
public AList latest(int x) {
AList sorted = sortByTime();
if (sorted == null) return null;
AList subList = sorted.sublist(this.list.size() - x + 1, x);
AList list = new AList();
for (ADataType obj : this.list) {
if (subList.contains(obj)) list.add(obj); // relies on equals(), which incorporates primaryTime
}
return list;
}
/**
* Compares this object to another as an identity comparison, in which the primary time of the objects are
* considered.
* @param o
* @return {@code true} if {@code this} and {@code o} have the same value and the same primary
* time.
*/
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (o == this) return true;
if (o.getClass() != getClass()) return false;
AList al = (AList) o;
return new EqualsBuilder()
.append(list, al.list)
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(59, 163)
.append(list)
.toHashCode();
}
/**
* Compares this object to another, considering only the value of the object, and not the primary time.
* @param o
* @return {@code true} if {@code this} and {@code o} have the same value.
*/
@Override
public boolean hasValue(ADataType o) {
if (o == null) return false;
if (o == this) return true;
if (o.getClass() != getClass()) return false;
AList al = (AList) o;
if (list.size() != al.list.size()) return false;
for (int i = 0; i <= list.size(); i ++) {
if ( ! list.get(i).hasValue(al.list.get(i)) ) {
return false;
}
}
return true;
}
@Override
public Iterator iterator() {
return list.iterator();
}
@Override
public Object toJavaObject() {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy