1 package org.rosuda.REngine;
3 // REngine library - Java client interface to R
4 // Copyright (C) 2004,2007,2008 Simon Urbanek
8 /** implementation of R-lists<br>
9 All lists (dotted-pair lists, language lists, expressions and vectors) are regarded as named generic vectors.
10 Note: This implementation has changed radically in Rserve 0.5!
12 This class inofficially implements the Map interface. Unfortunately a conflict in the Java iterface classes Map and List doesn't allow us to implement both officially. Most prominently the Map 'remove' method had to be renamed to removeByKey.
16 public class RList extends Vector implements List {
19 /** constructs an empty list */
20 public RList() { super(); names=null; }
22 /** constructs an initialized, unnamed list
23 * @param contents - an array of {@link REXP}s to use as contents of this list */
24 public RList(REXP[] contents) {
25 super(contents.length);
27 while (i<contents.length)
28 super.add(contents[i++]);
32 public RList(int initSize, boolean hasNames) {
35 if (hasNames) names=new Vector(initSize);
38 /** constructs an initialized, unnamed list
39 * @param contents - a {@link Collection} of {@link REXP}s to use as contents of this list */
40 public RList(Collection contents) {
45 /** constructs an initialized, named list. The length of the contents vector determines the length of the list.
46 * @param contents - an array of {@link REXP}s to use as contents of this list
47 * @param names - an array of {@link String}s to use as names */
48 public RList(REXP[] contents, String[] names) {
50 if (names!=null && names.length>0) {
51 this.names=new Vector(names.length);
53 while (i < names.length) this.names.add(names[i++]);
54 while (this.names.size()<size()) this.names.add(null);
58 /** constructs an initialized, named list. The size of the contents collection determines the length of the list.
59 * @param contents - a {@link Collection} of {@link REXP}s to use as contents of this list
60 * @param names - an array of {@link String}s to use as names */
61 public RList(Collection contents, String[] names) {
63 if (names!=null && names.length>0) {
64 this.names=new Vector(names.length);
66 while (i < names.length) this.names.add(names[i++]);
67 while (this.names.size()<size()) this.names.add(null);
71 /** constructs an initialized, named list. The size of the contents collection determines the length of the list.
72 * @param contents - a {@link Collection} of {@link REXP}s to use as contents of this list
73 * @param names - an {@link Collection} of {@link String}s to use as names */
74 public RList(Collection contents, Collection names) {
76 if (names!=null && names.size()>0) {
77 this.names=new Vector(names);
78 while (this.names.size()<size()) this.names.add(null);
82 /** checks whether this list is named or unnamed
83 * @return <code>true</code> if this list is named, <code>false</code> otherwise */
84 public boolean isNamed() {
88 /** get xpression given a key
90 @return value which corresponds to the given key or
91 <code>null</code> if the list is unnamed or key not found */
92 public REXP at(String v) {
93 if (names==null) return null;
94 int i = names.indexOf(v);
95 if (i < 0) return null;
96 return (REXP)elementAt(i);
99 /** get element at the specified position
101 @return value at the index or <code>null</code> if the index is out of bounds */
102 public REXP at(int i) {
103 return (i>=0 && i<size())?(REXP)elementAt(i):null;
106 /** return the key (name) at a given index
108 @return ket at the index - can be <code>null</code> is the list is unnamed or the index is out of range */
109 public String keyAt(int i) {
110 return (names==null || i<0 || i>=names.size())?null:(String)names.get(i);
113 /** set key at the given index. Using this method automatically makes the list a named one even if the key is <code>null</code>. Out of range operations are undefined (currently no-ops)
115 @param value key name */
116 public void setKeyAt(int i, String value) {
119 names = new Vector();
120 if (names.size() < size()) names.setSize(size());
121 if (i < size()) names.set(i, value);
124 /** returns all keys of the list
125 * @return array containing all keys or <code>null</code> if list unnamed */
126 public String[] keys() {
127 if (names==null) return null;
129 String k[] = new String[names.size()];
130 while (i < k.length) { k[i] = keyAt(i); i++; };
134 // --- overrides that sync names
136 public void add(int index, Object element) {
137 super.add(index, element);
138 if (names==null) return;
139 names.add(index, null);
142 public boolean add(Object element) {
149 public boolean addAll(Collection c) {
150 boolean ch = super.addAll(c);
151 if (names==null) return ch;
153 while (names.size()<l) names.add(null);
157 public boolean addAll(int index, Collection c) {
158 boolean ch = super.addAll(index, c);
159 if (names==null) return ch;
161 while (l-- > 0) names.add(index, null);
165 public void clear() {
170 public Object clone() {
171 return new RList(this, names);
174 public Object remove(int index) {
175 Object o = super.remove(index);
178 if (size()==0) names=null;
183 public boolean remove(Object elem) {
184 int i = indexOf(elem);
185 if (i<0) return false;
187 if (size()==0) names=null;
191 public boolean removeAll(Collection c) {
192 if (names==null) return super.removeAll(c);
193 boolean changed=false;
194 Iterator it = c.iterator();
196 changed|=remove(it.next());
200 public boolean retainAll(Collection c) {
201 if (names==null) return super.retainAll(c);
202 boolean rm[] = new boolean[size()];
203 boolean changed=false;
205 while (i<rm.length) {
206 changed|=rm[i]=!c.contains(get(i));
211 if (rm[i]) remove(i);
216 // --- old API mapping
217 public void removeAllElements() { clear(); }
218 public void insertElementAt(Object obj, int index) { add(index, obj); }
219 public void addElement(Object obj) { add(obj); }
220 public void removeElementAt(int index) { remove(index); }
221 public boolean removeElement(Object obj) { return remove(obj); }
225 public boolean containsKey(Object key) {
226 return (names==null)?false:names.contains(key);
229 public boolean containsValue(Object value) {
230 return contains(value);
233 /** NOTE: THIS IS UNIMPLEMENTED and always returns <code>null</code>! Due to the fact that R lists are not proper maps we canot maintain a set-view of the list */
234 public Set entrySet() {
238 public Object get(Object key) {
239 return at((String)key);
242 /** Note: sinde RList is not really a Map, the returned set is only an approximation as it cannot reference duplicate or null names that may exist in the list */
243 public Set keySet() {
244 if (names==null) return null;
245 return new HashSet(names);
248 public Object put(Object key, Object value) {
254 int p = names.indexOf(key);
256 return super.set(p, value);
261 names = new Vector(i+1);
262 while (names.size() < i) names.add(null);
267 public void putAll(Map t) {
269 // NOTE: this if branch is dead since RList cannot inherit from Map
270 if (t instanceof RList) { // we need some more sophistication for RLists as they may have null-names which we append
279 String key = l.keyAt(i);
288 Iterator i = ks.iterator();
289 while (i.hasNext()) {
290 Object key = i.next();
291 put(key, t.get(key));
296 public void putAll(RList t) {
297 if (t == null) return;
306 String key = l.keyAt(i);
315 public Object removeByKey(Object key) {
316 if (names==null) return null;
317 int i = names.indexOf(key);
318 if (i<0) return null;
319 Object o = elementAt(i);
321 names.removeElementAt(i);
325 public Collection values() {
330 public String toString() {
331 return "RList"+super.toString()+"{"+(isNamed()?"named,":"")+size()+"}";