Skip to content

Commit

Permalink
initial commit to add isTransition to htsjdk
Browse files Browse the repository at this point in the history
- added isTransition to VariantContext
- java8 sugar

- added error messages to asserts in FTPClientTest, since I had failures in travis that were hard to understand where they were comming from.
  • Loading branch information
yfarjoun committed Jan 8, 2016
1 parent 2c43dcf commit a2dc62b
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 102 deletions.
59 changes: 32 additions & 27 deletions src/java/htsjdk/samtools/util/CollectionUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

/**
* Small utility methods for dealing with collection classes.
Expand All @@ -42,34 +43,29 @@
public class CollectionUtil {

/** Simple case-insensitive lexical comparator of objects using their {@link Object#toString()} value. */
final public static Comparator<Object> OBJECT_TOSTRING_COMPARATOR = new Comparator<Object>() {
@Override
public int compare(final Object o1, final Object o2) {
return o1.toString().compareToIgnoreCase(o2.toString());
}
};
final public static Comparator<Object> OBJECT_TOSTRING_COMPARATOR = (o1, o2) -> o1.toString().compareToIgnoreCase(o2.toString());

public static <T> List<T> makeList (final T... list) {
final List<T> result = new ArrayList<T>();
public static <T> List<T> makeList(final T... list) {
final List<T> result = new ArrayList<>();
Collections.addAll(result, list);

return result;
}
public static <T> Set<T> makeSet (final T... list) {
final Set<T> result = new HashSet<T>();

public static <T> Set<T> makeSet(final T... list) {
final Set<T> result = new HashSet<>();
Collections.addAll(result, list);
return result;
}
public static <T> Collection<T> makeCollection (final Iterator<T> i) {
final List<T> list = new LinkedList<T>();

public static <T> Collection<T> makeCollection(final Iterator<T> i) {
final List<T> list = new LinkedList<>();
while (i.hasNext()) {
list.add(i.next());
}
return list;
}

/** Construct a string by toString()ing each item in the collection with inBetween between each item. */
public static String join(final Collection<?> items, final String inBetween) {
final StringBuilder builder = new StringBuilder();
Expand All @@ -86,7 +82,7 @@ public static <T> T getSoleElement(final Collection<T> items) {
throw new IllegalArgumentException(String.format("Expected a single element in %s, but found %s.", items, items.size()));
return items.iterator().next();
}

/** Simple multi-map for convenience of storing collections in map values. */
public static class MultiMap<K, V> extends HashMap<K, Collection<V>> {
public void append(final K k, final V v) {
Expand All @@ -101,25 +97,39 @@ public void appendAll(final K k, final Collection<? extends V> v) {

private void initializeKeyIfUninitialized(final K k) {
if (!this.containsKey(k))
this.put(k, new LinkedList<V>());
this.put(k, new LinkedList<>());
}
}

/**
/**
* Partitions a collection into groups based on a characteristics of that group. Partitions are embodied in a map, whose keys are the
* value of that characteristic, and the values are the partition of elements whose characteristic evaluate to that key.
*/
public static <K, V> Map<K,Collection<V>> partition(final Collection<V> collection, final Partitioner<V, K> p) {
final MultiMap<K, V> partitionToValues = new MultiMap<K, V>();
@Deprecated //use java8 .stream().collect(Collectors.groupingBy(()-> function)) instead
public static <K, V> Map<K, Collection<V>> partition(final Collection<V> collection, final Partitioner<V, K> p) {
final MultiMap<K, V> partitionToValues = new MultiMap<>();
for (final V entry : collection) {
partitionToValues.append(p.getPartition(entry), entry);
}
return partitionToValues;
}
@Deprecated //not needed, use Collectors.groupingBy instead
public static abstract class Partitioner<V, K> {
public abstract K getPartition(final V v);
}


/**
* Partitions a collection into groups based on a characteristics of that group. Partitions are embodied in a map, whose keys are the
* value of that characteristic, and the values are the partition of elements whose characteristic evaluate to that key.
*/
public static <K, V> Map<K, Collection<V>> partition(final Collection<V> collection, final Function<? super V, ? extends K> keyer) {
final MultiMap<K, V> partitionToValues = new MultiMap<>();
for (final V entry : collection) {
partitionToValues.append(keyer.apply(entry), entry);
}
return partitionToValues;
}

/**
* A defaulting map, which returns a default value when a value that does not exist in the map is looked up.
*
Expand All @@ -138,12 +148,7 @@ public static class DefaultingMap<K, V> extends HashMap<K, V> {

/** Creates a defaulting map which defaults to the provided value and with injecting-on-default disabled. */
public DefaultingMap(final V defaultValue) {
this(new Factory<V, K>() {
@Override
public V make(final K k) {
return defaultValue;
}
}, false);
this(k -> defaultValue, false);
}

/**
Expand Down
35 changes: 13 additions & 22 deletions src/java/htsjdk/variant/variantcontext/VariantContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

package htsjdk.variant.variantcontext;

import htsjdk.samtools.util.Tuple;
import htsjdk.tribble.Feature;
import htsjdk.tribble.TribbleException;
import htsjdk.tribble.util.ParsingUtils;
Expand All @@ -36,6 +37,7 @@
import htsjdk.variant.vcf.VCFHeaderLineType;

import java.io.Serializable;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand All @@ -47,6 +49,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
*
Expand Down Expand Up @@ -1687,30 +1690,19 @@ public boolean hasSymbolicAlleles() {
}

public static boolean hasSymbolicAlleles( final List<Allele> alleles ) {
for ( final Allele a: alleles ) {
if (a.isSymbolic()) {
return true;
}
}
return false;
return alleles.stream().anyMatch(Allele::isSymbolic);
}

public Allele getAltAlleleWithHighestAlleleCount() {
// optimization: for bi-allelic sites, just return the 1only alt allele
// optimization: for bi-allelic sites, just return the only alt allele
if ( isBiallelic() )
return getAlternateAllele(0);

Allele best = null;
int maxAC1 = 0;
for ( Allele a : getAlternateAlleles() ) {
final int ac = getCalledChrCount(a);
if ( ac >= maxAC1 ) {
maxAC1 = ac;
best = a;
}

}
return best;
return getAlternateAlleles().stream()
.map(allele -> new Tuple<>(allele, getCalledChrCount(allele)))
.max((alleleAndCount1, alleleAndCount2) -> Integer.compare(alleleAndCount1.b, alleleAndCount2.b))
.get()
.a;
}

/**
Expand All @@ -1730,10 +1722,9 @@ public int getAlleleIndex(final Allele allele) {
* @return a list of indices for each allele, in order
*/
public List<Integer> getAlleleIndices(final Collection<Allele> alleles) {
final List<Integer> indices = new LinkedList<Integer>();
for ( final Allele allele : alleles )
indices.add(getAlleleIndex(allele));
return indices;
return alleles.stream()
.map(this::getAlleleIndex)
.collect(Collectors.toCollection(() -> new ArrayList<>(alleles.size())));
}

public int[] getGLIndecesOfAlternateAllele(Allele targetAllele) {
Expand Down
60 changes: 55 additions & 5 deletions src/java/htsjdk/variant/variantcontext/VariantContextUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -165,7 +166,7 @@ public static Map<String, Object> calculateChromosomeCounts(VariantContext vc, M
*/
public static void calculateChromosomeCounts(VariantContextBuilder builder, boolean removeStaleValues) {
VariantContext vc = builder.make();
builder.attributes(calculateChromosomeCounts(vc, new HashMap<String, Object>(vc.getAttributes()), removeStaleValues, new HashSet<String>(0)));
builder.attributes(calculateChromosomeCounts(vc, new HashMap<>(vc.getAttributes()), removeStaleValues, new HashSet<>(0)));
}

/**
Expand All @@ -179,7 +180,7 @@ public static void calculateChromosomeCounts(VariantContextBuilder builder, bool
*/
public static void calculateChromosomeCounts(VariantContextBuilder builder, boolean removeStaleValues, final Set<String> founderIds) {
VariantContext vc = builder.make();
builder.attributes(calculateChromosomeCounts(vc, new HashMap<String, Object>(vc.getAttributes()), removeStaleValues, founderIds));
builder.attributes(calculateChromosomeCounts(vc, new HashMap<>(vc.getAttributes()), removeStaleValues, founderIds));
}

public final static VCFCompoundHeaderLine getMetaDataForField(final VCFHeader header, final String field) {
Expand Down Expand Up @@ -268,7 +269,7 @@ public static List<JexlVCMatchExp> initializeMatchExps(List<String> names, List<
* @return list of matches
*/
public static List<JexlVCMatchExp> initializeMatchExps(Map<String, String> names_and_exps) {
List<JexlVCMatchExp> exps = new ArrayList<JexlVCMatchExp>();
List<JexlVCMatchExp> exps = new ArrayList<>();

for ( Map.Entry<String, String> elt : names_and_exps.entrySet() ) {
String name = elt.getKey();
Expand All @@ -293,7 +294,7 @@ public static List<JexlVCMatchExp> initializeMatchExps(Map<String, String> names
* @return true if there is a match
*/
public static boolean match(VariantContext vc, JexlVCMatchExp exp) {
return match(vc,Arrays.asList(exp)).get(exp);
return match(vc, Collections.singletonList(exp)).get(exp);
}

/**
Expand All @@ -319,7 +320,7 @@ public static Map<JexlVCMatchExp, Boolean> match(VariantContext vc, Collection<J
* @return true if there is a match
*/
public static boolean match(VariantContext vc, Genotype g, JexlVCMatchExp exp) {
return match(vc,g,Arrays.asList(exp)).get(exp);
return match(vc,g, Collections.singletonList(exp)).get(exp);
}

/**
Expand All @@ -337,6 +338,55 @@ public static Map<JexlVCMatchExp, Boolean> match(VariantContext vc, Genotype g,
return new JEXLMap(exps,vc,g);
}

/**
* Answers if the provided variant is transitional (otherwise, it's transversional).
* Transitions:
* A->G
* G->A
* C->T
* T->C
* <p/>
* Transversions:
* A->C
* A->T
* C->A
* C->G
* G->C
* G->T
* T->A
* T->G
*
* @param vc a biallelic polymorphic SNP
* @return true if a transition and false if transversion
* @throws IllegalArgumentException if vc is monomorphic, not a SNP or not bi-allelic.
*/

static public boolean isTransition(final VariantContext vc) throws IllegalArgumentException {
final byte refAllele = vc.getReference().getBases()[0];
final Collection<Allele> altAlleles = vc.getAlternateAlleles();

if(vc.type == VariantContext.Type.NO_VARIATION) {
throw new IllegalArgumentException("Variant context is monomorphic: " + vc.toString());
}

if(vc.type != VariantContext.Type.SNP) {
throw new IllegalArgumentException("Variant context is not a SNP: " + vc.toString());
}

if(altAlleles.size() != 1 ) {
throw new IllegalArgumentException("Expected exactly 1 alternative Allele. Found: " + altAlleles.size());
}

final Byte altAllele = altAlleles.iterator().next().getBases()[0];

return (refAllele == 'A' && altAllele == 'G')
|| (refAllele == 'G' && altAllele == 'A')
|| (refAllele == 'C' && altAllele == 'T')
|| (refAllele == 'T' && altAllele == 'C');
}


/**
* Returns a newly allocated VC that is the same as VC, but without genotypes
* @param vc variant context
Expand Down
Loading

0 comments on commit a2dc62b

Please sign in to comment.