import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* A data store for a set of sequence features that supports efficient lookup of
*/
NCList<SequenceFeature> nestedFeatures;
+ /*
+ * Feature groups represented in the stored features
+ * (possibly including null)
+ */
+ Set<String> featureGroups;
+
/**
* Constructor
*/
public FeatureStore()
{
nonNestedFeatures = new ArrayList<SequenceFeature>();
+ featureGroups = new HashSet<String>();
+
// we only construct nonPositionalFeatures, contactFeatures
// or the NCList if we need to
}
*/
public boolean addFeature(SequenceFeature feature)
{
+ featureGroups.add(feature.getFeatureGroup());
+
boolean added = false;
if (feature.isContactFeature())
*
* @param sf
*/
- public boolean delete(SequenceFeature sf)
+ public synchronized boolean delete(SequenceFeature sf)
{
/*
* try the non-nested positional features first
removed = nestedFeatures.delete(sf);
}
+ if (removed)
+ {
+ /*
+ * if this was the only feature for its feature group,
+ * remove the group from the stored set
+ */
+ String featureGroup = sf.getFeatureGroup();
+ if (!findFeatureGroup(featureGroup))
+ {
+ featureGroups.remove(featureGroup);
+ }
+ }
+
return removed;
}
/**
+ * Scans all features to check whether the given feature group is found, and
+ * returns true if found, else false
+ *
+ * @param featureGroup
+ * @return
+ */
+ protected boolean findFeatureGroup(String featureGroup)
+ {
+ for (SequenceFeature sf : getFeatures())
+ {
+ String group = sf.getFeatureGroup();
+ if (group == featureGroup
+ || (group != null && group.equals(featureGroup)))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Answers true if this store has no features, else false
*
* @return
return !hasFeatures;
}
+
+ /**
+ * Answers the set of distinct feature groups stored, possibly including null,
+ * as an unmodifiable view of the set.
+ *
+ * @return
+ */
+ public Set<String> getFeatureGroups()
+ {
+ return Collections.unmodifiableSet(featureGroups);
+ }
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* A class that stores sequence features in a way that supports efficient
}
return false;
}
+
+ /**
+ * Returns a set of the distinct feature groups present in the collection. The
+ * set may include null.
+ *
+ * @return
+ */
+ public Set<String> getFeatureGroups()
+ {
+ Set<String> groups = new HashSet<String>();
+ for (FeatureStore featureSet : featureStore.values())
+ {
+ groups.addAll(featureSet.getFeatureGroups());
+ }
+ return groups;
+ }
}
import jalview.datamodel.SequenceFeature;
import java.util.List;
+import java.util.Set;
import org.testng.annotations.Test;
assertTrue(fs.delete(sf3));
assertTrue(fs.isEmpty()); // all gone
}
+
+ @Test(groups = "Functional")
+ public void testGetFeatureGroups()
+ {
+ FeatureStore fs = new FeatureStore();
+ assertTrue(fs.getFeatureGroups().isEmpty());
+
+ SequenceFeature sf1 = new SequenceFeature("Cath", "desc", 10, 20, 1f, "group1");
+ fs.addFeature(sf1);
+ Set<String> groups = fs.getFeatureGroups();
+ assertEquals(groups.size(), 1);
+ assertTrue(groups.contains("group1"));
+
+ /*
+ * add another feature of the same group, delete one, delete both
+ */
+ SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 20, 30, 1f, "group1");
+ fs.addFeature(sf2);
+ groups = fs.getFeatureGroups();
+ assertEquals(groups.size(), 1);
+ assertTrue(groups.contains("group1"));
+ fs.delete(sf2);
+ groups = fs.getFeatureGroups();
+ assertEquals(groups.size(), 1);
+ assertTrue(groups.contains("group1"));
+ fs.delete(sf1);
+ groups = fs.getFeatureGroups();
+ assertTrue(fs.getFeatureGroups().isEmpty());
+
+ SequenceFeature sf3 = new SequenceFeature("Cath", "desc", 20, 30, 1f, "group2");
+ fs.addFeature(sf3);
+ SequenceFeature sf4 = new SequenceFeature("Cath", "desc", 20, 30, 1f, "Group2");
+ fs.addFeature(sf4);
+ SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 20, 30, 1f, null);
+ fs.addFeature(sf5);
+ groups = fs.getFeatureGroups();
+ assertEquals(groups.size(), 3);
+ assertTrue(groups.contains("group2"));
+ assertTrue(groups.contains("Group2")); // case sensitive
+ assertTrue(groups.contains(null)); // null allowed
+
+ fs.delete(sf3);
+ groups = fs.getFeatureGroups();
+ assertEquals(groups.size(), 2);
+ assertFalse(groups.contains("group2"));
+ fs.delete(sf4);
+ groups = fs.getFeatureGroups();
+ assertEquals(groups.size(), 1);
+ assertFalse(groups.contains("Group2"));
+ fs.delete(sf5);
+ groups = fs.getFeatureGroups();
+ assertTrue(groups.isEmpty());
+ }
}
import jalview.datamodel.SequenceFeature;
import java.util.List;
+import java.util.Set;
import org.testng.annotations.Test;
sf.delete(sf1);
assertFalse(sf.hasFeatures());
}
+
+ @Test(groups = "Functional")
+ public void testGetFeatureGroups()
+ {
+ SequenceFeatures sf = new SequenceFeatures();
+ assertTrue(sf.getFeatureGroups().isEmpty());
+
+ SequenceFeature sf1 = new SequenceFeature("Pfam", "Desc", 10, 50, 0f,
+ "PfamGroup");
+ sf.add(sf1);
+ Set<String> groups = sf.getFeatureGroups();
+ assertEquals(groups.size(), 1);
+ assertTrue(groups.contains("PfamGroup"));
+
+ SequenceFeature sf2 = new SequenceFeature("Cath", "Desc", 10, 50, 0f,
+ null);
+ sf.add(sf2);
+ groups = sf.getFeatureGroups();
+ assertEquals(groups.size(), 2);
+ assertTrue(groups.contains("PfamGroup"));
+ assertTrue(groups.contains(null));
+
+ sf.delete(sf1);
+ sf.delete(sf2);
+ assertTrue(sf.getFeatureGroups().isEmpty());
+
+ SequenceFeature sf3 = new SequenceFeature("CDS", "", 10, 50, 0f,
+ "Ensembl");
+ sf.add(sf3);
+ SequenceFeature sf4 = new SequenceFeature("exon", "", 10, 50, 0f,
+ "Ensembl");
+ sf.add(sf4);
+ groups = sf.getFeatureGroups();
+ assertEquals(groups.size(), 1);
+ assertTrue(groups.contains("Ensembl"));
+
+ /*
+ * delete last Ensembl group feature from CDS features
+ * but still have one in exon features
+ */
+ sf.delete(sf3);
+ groups = sf.getFeatureGroups();
+ assertEquals(groups.size(), 1);
+ assertTrue(groups.contains("Ensembl"));
+ }
}