/* Copyright (C) 2002 Univ. of Massachusetts Amherst, Computer Science Dept.
This file is part of "MALLET" (MAchine Learning for LanguagE Toolkit).
http://www.cs.umass.edu/~mccallum/mallet
This software is provided under the terms of the Common Public License,
version 1.0, as published by http://www.opensource.org. For further
information, see the file `LICENSE' included with this distribution. */
/**
@author Andrew McCallum <a href="mailto:mccallum@cs.umass.edu">mccallum@cs.umass.edu</a>
*/
package edu.nd.nina.util;
import java.util.HashMap;
import java.util.HashSet;
public class PropertyList{
protected PropertyList next;
protected String key;
public static PropertyList add(String key, Object value, PropertyList rest) {
assert (key != null);
return new ObjectProperty(key, value, rest);
}
public static PropertyList add(String key, String value, PropertyList rest) {
assert (key != null);
return new ObjectProperty(key, value, rest);
}
public static PropertyList add(String key, double value, PropertyList rest) {
assert (key != null);
return new NumericProperty(key, value, rest);
}
public static PropertyList remove(String key, PropertyList rest) {
assert (key != null);
return new ObjectProperty(key, null, rest);
}
public Object lookupObject(String key) {
if (this.key.equals(key)) {
if (this instanceof ObjectProperty)
return ((ObjectProperty) this).value;
else if (this instanceof NumericProperty)
return new Double(((NumericProperty) this).value);
else
throw new IllegalStateException(
"Unrecognitized PropertyList entry.");
} else if (this.next == null) {
return null;
} else {
return next.lookupObject(key);
}
}
public double lookupNumber(String key) {
if (this.key.equals(key)) {
if (this instanceof NumericProperty)
return ((NumericProperty) this).value;
else if (this instanceof ObjectProperty) {
Object obj = ((ObjectProperty) this).value;
if (obj == null)
return 0;
// xxx Remove these? Use might ask for numericIterator expecting
// to get these (and not!)
if (obj instanceof Double)
return ((Double) obj).doubleValue();
if (obj instanceof Integer)
return ((Double) obj).intValue();
if (obj instanceof Float)
return ((Double) obj).floatValue();
if (obj instanceof Short)
return ((Double) obj).shortValue();
if (obj instanceof Long)
return ((Double) obj).longValue();
// xxx? throw new IllegalStateException
// ("Property is not numeric.");
return 0;
} else
throw new IllegalStateException(
"Unrecognitized PropertyList entry.");
} else if (this.next == null) {
return 0;
} else {
return next.lookupNumber(key);
}
}
public boolean hasProperty(String key) {
if (this.key.equals(key)) {
if (this instanceof ObjectProperty
&& ((ObjectProperty) this).value == null)
return false;
else
return true;
} else if (this.next == null) {
return false;
} else {
return next.hasProperty(key);
}
}
public Iterator iterator() {
return new Iterator(this);
}
public static PropertyList sumDuplicateKeyValues(PropertyList pl) {
return sumDuplicateKeyValues(pl, false);
}
// culotta 2/02/04: to increment counts of properties values.
public static PropertyList sumDuplicateKeyValues(PropertyList pl,
boolean ignoreZeros) {
if (!(pl instanceof NumericProperty))
throw new IllegalArgumentException(
"PropertyList must be Numeric to sum values");
HashMap<String, Double> key2value = new HashMap<String, Double>();
while (pl.iterator().hasNext()) {
pl.iterator().nextProperty ();
String key = pl.iterator().getKey();
double val = pl.iterator().getNumericValue();
Double storedValue = (Double) key2value.get(key);
if (storedValue == null)
key2value.put(key, new Double(val));
else
// sum stored value with current value
key2value.put(key, new Double(storedValue.doubleValue() + val));
}
PropertyList ret = null;
java.util.Iterator<String> hashIter = key2value.keySet().iterator();
while (hashIter.hasNext()) { // create new property list
String key = (String) hashIter.next();
double val = ((Double) key2value.get(key)).doubleValue();
if (ignoreZeros && val == 0.0)
continue;
ret = PropertyList.add(key, val, ret);
}
return ret;
}
public Iterator numericIterator() {
return new NumericIterator(this);
}
public Iterator objectIterator() {
return new ObjectIterator(this);
}
protected PropertyList() {
throw new IllegalArgumentException("Zero args constructor not allowed.");
}
protected PropertyList(String key, PropertyList rest) {
this.key = key;
this.next = rest;
}
public void print() {
if (this instanceof NumericProperty)
System.out.println(this.key.toString() + "="
+ ((NumericProperty) this).value);
else if (this instanceof ObjectProperty)
System.out.println(this.key.toString() + "="
+ ((ObjectProperty) this).value);
else
throw new IllegalArgumentException("Unrecognized PropertyList type");
if (this.next != null)
this.next.print();
}
public int size() {
PropertyList pl = this;
int size = 1;
while (pl.next != null) {
pl = pl.next;
size++;
}
return size;
}
private static class NumericProperty extends PropertyList {
protected double value;
public NumericProperty(String key, double value, PropertyList rest) {
super(key, rest);
this.value = value;
}
}
private static class ObjectProperty extends PropertyList {
protected Object value;
public ObjectProperty(String key, Object value, PropertyList rest) {
super(key, rest);
this.value = value;
}
}
public class Iterator implements java.util.Iterator<PropertyList> {
PropertyList property, nextProperty;
HashSet<String> deletedKeys = null;
boolean nextCalled = false;
boolean returnNumeric = true;
boolean returnObject = true;
public Iterator(PropertyList pl) {
property = findReturnablePropertyAtOrAfter(pl);
if (property == null)
nextProperty = null;
else
nextProperty = findReturnablePropertyAtOrAfter(property.next);
}
private PropertyList findReturnablePropertyAtOrAfter(
PropertyList property) {
while (property != null) {
if (property instanceof NumericProperty && returnNumeric) {
if (((NumericProperty) property).value == 0.0) {
if (deletedKeys == null)
deletedKeys = new HashSet<String>();
deletedKeys.add(property.key);
property = property.next;
} else
break;
} else if (property instanceof ObjectProperty && returnObject) {
if (((ObjectProperty) property).value == null) {
if (deletedKeys == null)
deletedKeys = new HashSet<String>();
deletedKeys.add(property.key);
property = property.next;
} else
break;
} else
throw new IllegalStateException(
"Unrecognized property type "
+ property.getClass().getName());
}
return property;
}
public boolean hasNext() {
return ((nextCalled && nextProperty != null) || (!nextCalled && property != null));
}
public boolean isNumeric() {
return (property instanceof NumericProperty);
}
public double getNumericValue() {
return ((NumericProperty) property).value;
}
public Object getObjectValue() {
return ((ObjectProperty) property).value;
}
public String getKey() {
return property.key;
}
public PropertyList nextProperty() {
if (nextCalled) {
property = nextProperty;
nextProperty = findReturnablePropertyAtOrAfter(property.next);
} else
nextCalled = true;
return property;
}
public PropertyList next() {
return nextProperty();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
public class NumericIterator extends Iterator {
public NumericIterator(PropertyList pl) {
super(pl);
this.returnObject = false;
}
}
public class ObjectIterator extends Iterator {
public ObjectIterator(PropertyList pl) {
super(pl);
this.returnNumeric = false;
}
}
// for fast merging of PropertLists
// gmann 8/14/6
public PropertyList last() {
if (next == null) {
return this;
} else
return next.last();
}
public PropertyList append(PropertyList nextPl)
throws UnsupportedOperationException {
if (this.next != null) {
throw new UnsupportedOperationException(
"PropertyList.java: Cannot append to middle of a list\n");
}
this.next = nextPl;
return last();
}
}