1 2 3 4 5 6 7 8 9 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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
package org.rosuda.JRI;
// JRclient library - client interface to Rserve, see http://www.rosuda.org/Rserve/
// Copyright (C) 2004 Simon Urbanek
// --- for licensing information see LICENSE file in the original JRclient distribution ---
import java.util.*;
/** implementation of R-lists<br>
This is rather preliminary and may change in future since it's not really proper.
The point is that the parser tries to interpret lists to be of the form entry=value,
where entry is stored in the "head" part, and value is stored in the "body" part.
Then using {@link #at(String)} it is possible to fetch "body" for a specific "head".
The terminology used is partly from hash fields - "keys" are the elements in "head"
and values are in "body" (see {@link #keys}).
<p>
On the other hand, R uses lists to store complex internal structures, which are not
parsed according to the structure - in that case "head" and "body" have to be evaluated
separately according to their meaning in that context.
@version $Id: RList.java 2720 2007-03-15 17:35:42Z urbanek $
*/
public class RList extends Object {
/** xpressions containing head, body and tag.
The terminology is a bit misleading (for historical reasons) - head corresponds to CAR, body to CDR and finally tag is TAG. */
public REXP head, body, tag;
/** cached keys (from TAG) */
String[] keys = null;
/** cached values(from CAR) */
REXP[] values = null;
/** flag denoting whether we need to re-fetch the cached values.<p><b.Note:</b> the current assumption is that the contents don't change after first retrieval - there is currently no recursive check! */
boolean dirtyCache = true;
/** constructs an empty list */
public RList() { head=body=tag=null; }
/** fake constructor to keep compatibility with Rserve (for now, will be gone soon) */
public RList(RVector v) {
Vector n = v.getNames();
if (n != null) {
keys = new String[n.size()];
n.copyInto(keys);
}
values=new REXP[v.size()];
v.copyInto(values);
dirtyCache=false;
// head,tail,tag are all invalid!
}
/** constructs an initialized list
@param h head xpression
@param b body xpression */
public RList(REXP h, REXP b) { head=h; body=b; tag=null; }
/** constructs an initialized list
@param h head xpression (CAR)
@param t tag xpression (TAG)
@param b body/tail xpression (CDR)
*/
public RList(REXP h, REXP t, REXP b) { head=h; body=b; tag=t; }
/** get head xpression (CAR)
@return head xpression */
public REXP getHead() { return head; }
/** get body xpression (CDR)
@return body xpression */
public REXP getBody() { return body; }
/** get tag xpression
@return tag xpression */
public REXP getTag() { return tag; }
/** internal function that updates cached vectors
@return <code>true</code> if the conversion was successful */
boolean updateVec() {
if (!dirtyCache) return true;
// we do NOT run it recursively, because in most cases only once instance is asked
RList cur = this;
int l = 0;
while (cur!=null) {
l++;
REXP bd = cur.getBody();
cur = (bd==null)?null:bd.asList();
}
keys=new String[l];
values=new REXP[l];
cur = this;
l=0;
while (cur != null) {
REXP x = cur.getTag();
if (x!=null) keys[l]=x.asSymbolName();
values[l] = cur.getHead();
REXP bd = cur.getBody();
cur = (bd==null)?null:bd.asList();
l++;
}
dirtyCache=false;
return true;
}
/** get xpression given a key
@param v key
@return xpression which corresponds to the given key or
<code>null</code> if list is not standartized or key not found */
public REXP at(String v) {
if (!updateVec() || keys==null || values==null) return null;
int i=0;
while (i<keys.length) {
if (keys[i].compareTo(v)==0) return values[i];
i++;
}
return null;
}
/** get element at the specified position
@param i index
@return xpression at the index or <code>null</code> if list is not standartized or
if index out of bounds */
public REXP at(int i) {
return (!updateVec() || values==null || i<0 || i>=values.length)?null:values[i];
}
/** returns all keys of the list
@return array containing all keys or <code>null</code> if list is not standartized */
public String[] keys() {
return (!updateVec())?null:this.keys;
}
}
|