package edu.stanford.nlp.ling; import edu.stanford.nlp.stats.ClassicCounter; import edu.stanford.nlp.stats.Counter; import java.util.Collection; import java.util.Collections; /** * A basic implementation of the Datum interface that can be constructed with a * Collection of features and one more more labels. The features must be * specified at construction, but the labels can be set and/or changed later. * * @author Jenny Finkel * <a href="mailto:jrfinkel@stanford.edu">jrfinkel@stanford.edu</a> * @author Sarah Spikes (sdspikes@stanford.edu) [templatized] * * @param <L> * The type of the label of the datum * @param <F> * The type of individual features stored in the datum */ public class RVFDatum<L, F> implements Datum<L, F> { private static final long serialVersionUID = -255312811814660438L; /** * features for this Datum */ private final Counter<F> features; /** * labels for this Datum. Invariant: always non-null */ private L label; // = null; /** * Id of this instance */ private String id = null; /** * Constructs a new RVFDatum with the given features and label. */ public RVFDatum(Counter<F> features, L label) { this.features = features; setLabel(label); } /** * Constructs a new RVFDatum taking the data from a Datum. <i>Implementation * note:</i> This constructor allocates its own counter over features, but is * only guaranteed correct if the label and feature names are immutable. * * @param m The Datum to copy. */ public RVFDatum(Datum<L, F> m) { this.features = new ClassicCounter<>(); for (F key : m.asFeatures()) { features.incrementCount(key, 1.0); } setLabel(m.label()); } /** * Constructs a new RVFDatum with the given features and no labels. */ public RVFDatum(Counter<F> features) { this.features = features; } /** * Constructs a new RVFDatum with no features or labels. */ public RVFDatum() { this((ClassicCounter<F>) null); } /** * Returns the Counter of features and values */ public Counter<F> asFeaturesCounter() { return features; } /** * Returns the list of features without values */ public Collection<F> asFeatures() { return features.keySet(); } /** * Removes all currently assigned Labels for this Datum then adds the given * Label. Calling <tt>setLabel(null)</tt> effectively clears all labels. */ public void setLabel(L label) { this.label = label; } /** * Sets id for this instance * @param id */ public void setID(String id){ this.id = id; } /** * Returns a String representation of this BasicDatum (lists features and * labels). */ @Override public String toString() { return "RVFDatum[id="+id+", features=" + asFeaturesCounter() + ",label=" + label() + "]"; } public L label() { return label; } public Collection<L> labels() { return Collections.singletonList(label); } public double getFeatureCount(F feature) { return features.getCount(feature); } public String id(){ return id; } /** * Returns whether the given RVFDatum contains the same features with the same * values as this RVFDatum. An RVFDatum can only be equal to another RVFDatum. * <i>Implementation note:</i> Doesn't check the labels, should we change * this? */ @Override @SuppressWarnings("unchecked") public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof RVFDatum)) { return (false); } RVFDatum<L, F> d = (RVFDatum<L, F>) o; return features.equals(d.asFeaturesCounter()); } /** {@inheritDoc} */ @Override public int hashCode() { return features.hashCode(); } }