package beast.evolution.alignment; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; import beast.core.Description; import beast.core.Input; @Description("A TaxonSet is an ordered set of taxa. The order on the taxa is provided at the time of construction" + " either from a list of taxon objects or an alignment.") public class TaxonSet extends Taxon { final public Input<List<Taxon>> taxonsetInput = new Input<>("taxon", "list of taxa making up the set", new ArrayList<>()); final public Input<Alignment> alignmentInput = new Input<>("alignment", "alignment where each sequence represents a taxon"); protected List<String> taxaNames; protected List<Taxon> taxonList; public TaxonSet() { } public TaxonSet(final List<Taxon> taxa) { taxonsetInput.setValue(taxa, this); initAndValidate(); } public TaxonSet(final Alignment alignment) { alignmentInput.setValue(alignment, this); initAndValidate(); } // for testing purposes (Huw) public TaxonSet(final String id, final List<Taxon> taxa) { setID(id); taxonsetInput.setValue(taxa, this); initAndValidate(); } @Override public void initAndValidate() { taxonList = taxonsetInput.get(); if (alignmentInput.get() != null) { if (taxonList.size() > 0) { throw new IllegalArgumentException("Only one of taxon and alignment should be specified, not both (id=" + getID() + ")."); } taxaNames = alignmentInput.get().taxaNames; } else { if (taxonList.size() == 0) { throw new IllegalArgumentException(getID() + ": Either taxon or alignment should be specified (id=" + getID() + ")."); } taxaNames = new ArrayList<>(); for (final Taxon taxon : taxonList) { taxaNames.add(taxon.getID()); } } } public Set<Taxon> getTaxonSet() { final Set<Taxon> unorderedTaxa = new HashSet<>(taxonList); return unorderedTaxa; } /** * @return an unmodifiable list of taxa names as strings. */ public List<String> asStringList() { if (taxaNames == null) return null; return Collections.unmodifiableList(taxaNames); } /** * @return the taxa names as a set of strings. */ public Set<String> getTaxaNames() { return new TreeSet<>(taxaNames); } /** * @return the ID of the i'th taxon. */ public String getTaxonId(int taxonIndex) { return taxaNames.get(taxonIndex); } /** * return index of given Taxon name * @param id * @return -1 if not found */ public int getTaxonIndex(String id) { for (int i = 0; i < taxaNames.size(); i++) { if (getTaxonId(i).contentEquals(id)) return i; } return -1; } // convenience methods public boolean containsAny(final Collection<String> taxa) { final List<String> me = asStringList(); for (final String taxon : taxa ) { if (me.contains(taxon)) { return true; } } return false; } public boolean containsAll(final Collection<String> taxa) { final List<String> me = asStringList(); for (final String taxon : taxa ) { if (!me.contains(taxon)) { return false; } } return true; } /** * @return true if at least 1 member of taxa contained in this set. * @param taxa a collection of taxa */ public boolean containsAny(final TaxonSet taxa) { return containsAny(taxa.asStringList()); } /** * @return true if taxa is a subset of this set * @param taxa */ public boolean containsAll(final TaxonSet taxa) { return containsAll(taxa.asStringList()); } /** * @return number of taxa in this taxon set */ public int getTaxonCount() { if (taxaNames == null) return 0; return taxaNames.size(); } /** * @return number of taxa in this taxon set * @deprecated Exists only for consistency with method in Alignment. Use * getTaxonCount() instead. */ @Deprecated public int getNrTaxa() { return getTaxonCount(); } @Override public String toString() { return toString("\t"); } @Override protected String toString(String indent) { final StringBuilder buf = new StringBuilder(); buf.append(indent).append(getID()).append("\n"); indent += "\t"; for (final Taxon taxon : taxonsetInput.get()) { buf.append(taxon.toString(indent)); } return buf.toString(); } }