class Attributes(UserList.UserList):
    def __init__(self, attributes = []):
        self.data = attributes

    def has_values(self, test_values):
        if len(test_values) != len(self): return False
        for i in range(len(test_values)):
            test_value = test_values[i]
            if self.data[i].is_continuous(): continue 
            if not self.data[i].has_value(test_value): return False
        return True
    
    def has_continuous(self):
        for attribute in self.data:
            if attribute.is_continuous(): 
                return True
        return False
    
    def subset(self, indices):
        return [self.data[index] for index in indices]

    def discretise(self, discretised_attributes):
        for disc_attr in discretised_attributes:
            self.data[disc_attr.index] = disc_attr
            
    def empty_decision_stumps(self, ignore_attributes, klass):
        filtered = filter(lambda attribute: attribute not in ignore_attributes, self.data)
        return [ds.DecisionStump(attribute, klass) for attribute in filtered]

    def remove_attributes(self, attributes):
        for attribute in attributes:
            self.remove(attribute)
        self.reset_indices()
            
    def reset_indices(self):
        for i in range(len(self.data)):
            self.data[i].index = i
            
    def continuous_attribute_indices(self):
        return [atr.index for atr in self.data if atr.is_continuous()]
    
    def empty_freq_dists(self):
        return dict([(attribute, attribute.empty_freq_dists()) for attribute in self.data])
        
    def __str__(self):
        return '[' + ', '.join([each.__str__() for each in self]) + ']'
            
def fact(n):
    if n==0 or n==1: return 1
    return n * fact(n -1)

def ncr(n, r):
    return fact(n) / (fact(r) * fact(n -r))