DataPointSorter.java

/*
 * (C) Copyright 2015-2017 by MSDK Development Team
 *
 * This software is dual-licensed under either
 *
 * (a) the terms of the GNU Lesser General Public License version 2.1 as published by the Free
 * Software Foundation
 *
 * or (per the licensee's choosing)
 *
 * (b) the terms of the Eclipse Public License v1.0 as published by the Eclipse Foundation.
 */

package io.github.msdk.util;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * <p>
 * DataPointSorter class.
 * </p>
 */
public class DataPointSorter {

  public enum SortingProperty {
    MZ, INTENSITY
  }

  public enum SortingDirection {
    ASCENDING, DESCENDING
  }

  private static class DataPointComparator implements Comparator<Integer> {

    private final double mzBuffer[];
    private final float intensityBuffer[];
    private final SortingProperty prop;
    private final SortingDirection dir;

    DataPointComparator(final double mzBuffer[], final float intensityBuffer[],
        SortingProperty prop, SortingDirection dir) {
      this.mzBuffer = mzBuffer;
      this.intensityBuffer = intensityBuffer;
      this.prop = prop;
      this.dir = dir;
    }

    @Override
    public int compare(Integer i1, Integer i2) {
      switch (prop) {
        case INTENSITY:
          if (dir == SortingDirection.ASCENDING)
            return Float.compare(intensityBuffer[i1], intensityBuffer[i2]);
          else
            return Float.compare(intensityBuffer[i2], intensityBuffer[i1]);
        case MZ:
          if (dir == SortingDirection.ASCENDING)
            return Double.compare(mzBuffer[i1], mzBuffer[i2]);
          else
            return Double.compare(mzBuffer[i2], mzBuffer[i1]);
      }
      return 0;
    }

  }

  /**
   * Sort the given data points by m/z order
   *
   * @param mzBuffer an array of double.
   * @param intensityBuffer an array of float.
   * @param size a int.
   * @param prop a {@link io.github.msdk.util.DataPointSorter.SortingProperty} object.
   * @param dir a {@link io.github.msdk.util.DataPointSorter.SortingDirection} object.
   */
  public static void sortDataPoints(final double mzBuffer[], final float intensityBuffer[],
      final int size, SortingProperty prop, SortingDirection dir) {

    // Use Collections.sort to obtain index mapping from old arrays to the
    // new sorted array
    final List<Integer> idx = new ArrayList<>(size);
    for (int i = 0; i < size; i++)
      idx.add(i);
    Comparator<Integer> comp = new DataPointComparator(mzBuffer, intensityBuffer, prop, dir);

    Collections.sort(idx, comp);
    // Remap the values according to the index map idx
    remapArray(mzBuffer, idx);
    remapArray(intensityBuffer, idx);

  }

  private static void remapArray(Object array, List<Integer> indices) {

    // Make a copy of indices, to prevent modifying the list
    List<Integer> idx = new ArrayList<>(indices);

    for (int i = 0; i < idx.size(); i++) {
      final int newIndex = idx.get(i);
      if (newIndex == i)
        continue;

      Object tmp = Array.get(array, i);
      Array.set(array, i, Array.get(array, newIndex));

      final int swapIndex = idx.indexOf(i);
      Array.set(array, newIndex, tmp);
      idx.set(swapIndex, newIndex);
      idx.set(i, i);
    }
  }

  /**
   * Sort the given data points by RT order
   *
   * @param rtBuffer an array
   * @param mzBuffer an array of double.
   * @param intensityBuffer an array of float.
   * @param size a int.
   */
  public static void sortDataPoints(final Float rtBuffer[], final double mzBuffer[],
      final float intensityBuffer[], final int size) {

    // Use Collections.sort to obtain index mapping from old arrays to the
    // new sorted array
    final List<Integer> idx = new ArrayList<>(size);
    for (int i = 0; i < size; i++)
      idx.add(i);
    Collections.sort(idx, new Comparator<Integer>() {
      public int compare(Integer i1, Integer i2) {
        return rtBuffer[i1].compareTo(rtBuffer[i2]);
      }
    });

    // Remap the values according to the index map idx
    remapArray(rtBuffer, idx);
    remapArray(mzBuffer, idx);
    remapArray(intensityBuffer, idx);

  }

}