/* * BioJava development code * * This code may be freely distributed and modified under the * terms of the GNU Lesser General Public Licence. This should * be distributed with the code. If you do not have a copy, * see: * * http://www.gnu.org/copyleft/lesser.html * * Copyright for this code is held jointly by the individual * authors. These should be listed in @author doc comments. * * For more information on the BioJava project and its aims, * or to join the biojava-l mailing list, visit the home page * at: * * http://www.biojava.org/ * */ package org.biojava.bio.symbol; /** * Factory methods for constructing useful views onto SymbolLists. * * @author Thomas Down * @author Matthew Pocock * @since 1.1 */ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.biojava.bio.seq.SequenceIterator; import org.biojava.utils.ChangeVetoException; import org.biojava.utils.Unchangeable; /** * Tools class for constructing views of SymbolList objects. * * @since 1.2 */ public final class SymbolListViews { private SymbolListViews() {} /** * An n-th order view of another SymbolList. *

* In practice, what this means is that you can view a DNA sequence into an * overlapping dinucleotide sequence without having to do any work yourself. *

* * @param source The underlying SymbolList to view * @param order The window size */ public static SymbolList orderNSymbolList(SymbolList source, int order) throws IllegalAlphabetException { if (order == 1) return source; return new OrderNSymbolList(source, order); } /** * A view of windows onto another SymbolList. *

* In practice, what this means is that you can view a DNA sequence as codons which * do not overlap. *

* * @param source The underlying SymbolList to view * @param wsize The window size. * @throws IllegalArgumentException if the symbollist length isn't an integer multiple of wsize. */ public static SymbolList windowedSymbolList(SymbolList source, int wsize) throws IllegalArgumentException { return new WindowedSymbolList(source, wsize); } /** * A reversed view onto a SymbolList. * * @param symbols the SymbolList to reverse. */ public static SymbolList reverse(SymbolList symbols) { return new ReverseSymbolList(symbols); } /** * Provides a 'translated' view of an underlying SymbolList. *

* This method allows you to translate from one alphabet into another, so * for example, you could translate from DNA-triplets into amino-acids. You * could also translate from DNA-dinucleotide into the 'twist' structural * metric, or any other translation that takes your fancy. *

*

* The actual mapping from source to view Symbol is encapsulated in a * TranslationTable object. *

*

* The translated SymbolList will be the same length as the source, and each * Symbol in the view will correspond to a single Symbol in the source. *

* * @param symbols a SymbolList to translate. * @param table a translation table for mapping symbols. */ public static SymbolList translate(SymbolList symbols, TranslationTable table) throws IllegalAlphabetException { return new TranslatedSymbolList(symbols, table); } /** * Construct an alignment of the SymbolLists contained in the values collection * of labelToSymList. * * @param labelToSymList A Map containing label -> SymbolList mappings */ public static Alignment alignment(Map labelToSymList) throws IllegalArgumentException { return new SimpleAlignment(labelToSymList); } /** * View a SymbolList over a cross-product Alphabet as an Alignment. * * @param labels a List of labels, which should be the same length * as the order symList's Alphabet. * @param symList a SymbolList over a cross-product alphabet. */ public static Alignment alignment(List labels, SymbolList symList) throws IllegalArgumentException { return new SymListAsAlignment(labels, symList); } /** * View a portion of a SymbolList. Unlike SymbolList.subList, this * method is guarenteed to return a view, which will change when * the underlying SymbolList is modified. * * @param parent the SymbolList to view * @param start the first index to include in the view * @param end the last index to include in the view * @throws IllegalArgumentException if the start or end points fall outside the parent SymbolList. * @since 1.4 */ public static SymbolList subList(SymbolList parent, int start, int end) throws IllegalArgumentException { if (start < 1 || end > parent.length()) { throw new IndexOutOfBoundsException( "Sublist index out of bounds " + parent.length() + ":" + start + "," + end ); } if (end < start) { throw new IllegalArgumentException( "end must not be lower than start: start=" + start + ", end=" + end ); } return new SubList(parent, start, end); } /** * Get a new immutable, empty symbol list with the given alphabet. * * @since 1.4 * @param alpha the Alphabet this symbol list is over * @return a new empty SymbolList */ public static SymbolList emptyList(Alphabet alpha) { return new EmptySymbolList(alpha); } private static class SymListAsAlignment extends Unchangeable implements Alignment { private final SymbolList symList; private final List labels; public SymListAsAlignment(List labels, SymbolList symList) { if(labels.size() != symList.getAlphabet().getAlphabets().size()) { throw new IllegalArgumentException("There must be one label per symbol list"); } this.labels = Collections.unmodifiableList(new ArrayList(labels)); this.symList = symList; } public List getLabels() { return labels; } public SequenceIterator sequenceIterator() { throw new UnsupportedOperationException("This method sucks"); } public Iterator symbolListIterator() { return new Alignment.SymbolListIterator(this); } public Symbol symbolAt(Object label, int column) { BasisSymbol sym = (BasisSymbol) symList.symbolAt(column); return (Symbol) sym.getSymbols().get(labels.indexOf(label)); } public SymbolList symbolListForLabel(Object label) { return new IndexedSymbolList(symList, labels.indexOf(label)); } public Alphabet getAlphabet() { return symList.getAlphabet(); } public Iterator iterator() { return symList.iterator(); } public int length() { return symList.length(); } public String seqString() { return symList.seqString(); } public SymbolList subList(int start, int end) throws IndexOutOfBoundsException { return symList.subList(start, end); } public String subStr(int start, int end) throws IndexOutOfBoundsException { return symList.subStr(start, end); } public void edit(Edit edit) throws IndexOutOfBoundsException, IllegalAlphabetException, ChangeVetoException { symList.edit(edit); } public List toList() { return symList.toList(); } public Symbol symbolAt(int indx) throws IndexOutOfBoundsException { return symList.symbolAt(indx); } public Alignment subAlignment(Set labels, Location loc) { throw new UnsupportedOperationException("Fixme: this needs to be implemented"); } } private static class IndexedSymbolList extends AbstractSymbolList { private final int indx; private final SymbolList symList; public IndexedSymbolList(SymbolList symList, int indx) throws IllegalArgumentException { if(indx >= symList.getAlphabet().getAlphabets().size()) { throw new IllegalArgumentException("index too high"); } this.indx = indx; this.symList = symList; } public Alphabet getAlphabet() { return (Alphabet) symList.getAlphabet().getAlphabets().get(indx); } public int length() { return symList.length(); } public Symbol symbolAt(int indx) throws IndexOutOfBoundsException { return (Symbol) ((BasisSymbol) symList.symbolAt(indx)).getSymbols().get(this.indx); } } }