/******************************************************************************
 *                   Confidential Proprietary                                 *
 *         (c) Copyright Haifeng Li 2011, All Rights Reserved                 *
 ******************************************************************************/

package smile.feature;

import java.util.HashMap;
import java.util.Map;

/**
 * The bag-of-words feature of text used in natural language
 * processing and information retrieval. In this model, a text (such as a
 * sentence or a document) is represented as an unordered collection of words,
 * disregarding grammar and even word order. This is a generic implementations.
 * Thus, it can be used for sequences of any (discrete) data types with limited
 * number of values.
 * 
 * @author Haifeng Li
 */
public class Bag<T> {
    /**
     * The mapping from feature words to indices.
     */
    private Map<T, Integer> features;

    /**
     * True to check if feature words appear in a document instead of their
     * frequencies.
     */
    private boolean binary;

    /**
     * Constructor.
     * @param features the list of feature objects.
     */
    public Bag(T[] features) {
        this(features, false);
    }

    /**
     * Constructor.
     * @param features the list of feature objects.
     * @param binary true to check if feature object appear in a collection
     * instead of their frequencies.
     */
    public Bag(T[] features, boolean binary) {
        this.binary = binary;
        this.features = new HashMap<T, Integer>();
        for (int i = 0; i < features.length; i++) {
            this.features.put(features[i], i);
        }
    }
    
    /**
     * Returns the bag-of-words features of a document. The features are real-valued
     * in convenience of most learning algorithms although they take only integer
     * or binary values.
     */
    public double[] feature(T[] x) {
        double[] bag = new double[features.size()];

        if (binary) {
            for (T word : x) {
                Integer f = features.get(word);
                if (f != null) {
                    bag[f] = 1.0;
                }
            }
        } else {
            for (T word : x) {
                Integer f = features.get(word);
                if (f != null) {
                    bag[f]++;
                }
            }
        }

        return bag;
    }
}

@@ -1317,25 +1317,167 @@
 ure objects.
+ The feature objects should be unique in the list.%0A     * Note that the Bag class doesn't learn the features, but just use them as attributes.
 %0A
-
      * @para
@@ -1733,16 +1733,23 @@
 (int i =
+ 0, k =
  0; i %3C 
@@ -1768,24 +1768,87 @@
 gth; i++) %7B%0A
+            if (!this.features.containsKey(features%5Bi%5D)) %7B%0A    
             
@@ -1882,11 +1882,27 @@
 i%5D, 
-i);
+k++);%0A            %7D
 %0A   

add sanity check in Bag constructor