001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojava.nbio.core.sequence.views; 022 023import org.biojava.nbio.core.sequence.template.Compound; 024import org.biojava.nbio.core.sequence.template.Sequence; 025import org.biojava.nbio.core.sequence.template.SequenceView; 026 027import java.util.Iterator; 028import java.util.List; 029import java.util.NoSuchElementException; 030 031/** 032 * A sliding window view of a sequence which does not implement any 033 * interfaces like {@link Sequence} because they do not fit how this works. 034 * For each index requested we return a SequenceView or List of compounds back. 035 * 036 * If you perform a view on a Sequence whose length is not a multiple of the 037 * window the final window will be omitted i.e. if we have the sequence AGCGG 038 * and a window of 3 then you will only see AGC since GG exceeds the calculated 039 * length of this sequence. 040 * 041 * Because this does not implement a Sequence interface we do not recommend 042 * passing this class around. If you need to represent a windowed sequence 043 * as a real Sequence then translate it into a new Compound 044 * 045 * @author ayates 046 * 047 * @param <C> The type of compound we return from a window 048 */ 049public class WindowedSequence<C extends Compound> implements Iterable<SequenceView<C>> { 050 051 private final Sequence<C> sequence; 052 private final int windowSize; 053 054 public WindowedSequence(Sequence<C> sequence, int windowSize) { 055 this.sequence = sequence; 056 this.windowSize = windowSize; 057 } 058 059 /** 060 * Access the current window size 061 */ 062 public int getWindowSize() { 063 return windowSize; 064 } 065 066 /** 067 * Access the sequence which backs this window 068 */ 069 public Sequence<C> getBackingSequence() { 070 return sequence; 071 } 072 073 /** 074 * Calculates start index according to the equation start = ( (index-1) - 075 * windowSize) +1 076 */ 077 protected int toStartIndex(int index) { 078 return ((index - 1) * getWindowSize()) + 1; 079 } 080 081 /** 082 * Returns the size of the windowed sequence which is the length by the 083 * window size. Trailing Compounds are omitted. 084 */ 085 public int getLength() { 086 return getBackingSequence().getLength() / getWindowSize(); 087 } 088 089 /** 090 * For a given position into the windowed view this will return those 091 * compounds we can see in the window. i.e. in the sequence AGGCCT requesting 092 * index 1 returns AGG and requesting index 2 return CCT. 093 * 094 * @param index Windowed index position 095 * @return The List of compounds 096 */ 097 public List<C> getCompounds(int index) { 098 return get(index).getAsList(); 099 } 100 101 /** 102 * Returns the window specified at the given index in offsets i.e. asking 103 * for position 2 in a moving window sequence of size 3 will get you 104 * the window starting at position 4. 105 */ 106 public SequenceView<C> get(int index) { 107 int start = toStartIndex(index); 108 int end = index + (getWindowSize() - 1); 109 return getBackingSequence().getSubSequence(start, end); 110 } 111 112 /** 113 * Returns an iterator which will return the windows in a sequence in 114 * sequential order. 115 */ 116 @Override 117 public Iterator<SequenceView<C>> iterator() { 118 return new WindowedSequenceIterator<C>(this); 119 } 120 121 /** 122 * Iterator of all List of compounds available in a windowed sequence. 123 */ 124 private static class WindowedSequenceIterator<C extends Compound> implements Iterator<SequenceView<C>> { 125 126 private final int end; 127 private final int window; 128 private final int offset; 129 private int currentIndex = 1; 130 private final Sequence<C> seq; 131 132 public WindowedSequenceIterator(WindowedSequence<C> sequence) { 133 this.window = sequence.getWindowSize(); 134 this.offset = window - 1; 135 this.seq = sequence.getBackingSequence(); 136 this.end = seq.getLength(); 137 } 138 139 @Override 140 public boolean hasNext() { 141 return (currentIndex+offset) <= end; 142 } 143 144 @Override 145 public SequenceView<C> next() { 146 if(!hasNext()){ 147 throw new NoSuchElementException(); 148 } 149 SequenceView<C> v = seq.getSubSequence(currentIndex, currentIndex + offset); 150 currentIndex = currentIndex + window; 151 return v; 152 } 153 154 @Override 155 public void remove() { 156 throw new UnsupportedOperationException("Cannot remove from a Windowed view"); 157 } 158 } 159}