001 /**
002 * Copyright (c) 2010, SIB. All rights reserved.
003 *
004 * SIB (Swiss Institute of Bioinformatics) - http://www.isb-sib.ch Host -
005 * https://sourceforge.net/projects/javaprotlib/
006 *
007 * Redistribution and use in source and binary forms, with or without
008 * modification, are permitted provided that the following conditions are met:
009 * Redistributions of source code must retain the above copyright notice, this
010 * list of conditions and the following disclaimer. Redistributions in binary
011 * form must reproduce the above copyright notice, this list of conditions and
012 * the following disclaimer in the documentation and/or other materials provided
013 * with the distribution. Neither the name of the SIB/GENEBIO nor the names of
014 * its contributors may be used to endorse or promote products derived from this
015 * software without specific prior written permission.
016 *
017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
020 * ARE DISCLAIMED. IN NO EVENT SHALL SIB/GENEBIO BE LIABLE FOR ANY DIRECT,
021 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
024 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027 */
028 package org.expasy.jpl.commons.collection;
029
030
031 import java.util.ArrayList;
032 import java.util.Arrays;
033 import java.util.List;
034 import org.apache.commons.collections15.Transformer;
035 import org.apache.commons.math.util.MathUtils;
036 import org.expasy.jpl.commons.collection.sorter.AbstractDoublesArrayIndexComparator;
037 import org.expasy.jpl.commons.collection.sorter.AbstractIntsArrayIndexComparator;
038 import org.expasy.jpl.commons.collection.sorter.ArrayIndexComparator;
039 import org.expasy.jpl.commons.collection.sorter.ArrayIndexSorter;
040
041
042 /**
043 * Provides static generic methods on primitive arrays.
044 *
045 * @author nikitin
046 *
047 * @version 1.0
048 *
049 */
050 public final class PrimitiveArrayUtils {
051
052 /** simply reverse the array */
053 public static void reverse(int[] b) {
054 int left = 0; // index of leftmost element
055 int right = b.length - 1; // index of rightmost element
056
057 while (left < right) {
058 // exchange the left and right elements
059 int temp = b[left];
060 b[left] = b[right];
061 b[right] = temp;
062
063 // move the bounds toward the center
064 left++;
065 right--;
066 }
067 }
068
069 /**
070 * Map the objects found at given indices.
071 *
072 * @param objects the objects to map.
073 * @param indices the indices of objects array.
074 * @return an array of mapped {@code Object}s.
075 */
076 public static Object[] mapping(final Object[] objects, final int[] indices) {
077
078 if (indices.length > objects.length) {
079 throw new IllegalArgumentException("too many indices");
080 }
081
082 final Object[] values = new Object[indices.length];
083 int i = 0;
084 for (final int index : indices) {
085 values[i++] = objects[index];
086 }
087
088 return values;
089 }
090
091 /**
092 * Map the integers found at given indices.
093 *
094 * @param array the integers to map.
095 * @param indices the indices of objects array.
096 * @return an array of mapped {@code int}s.
097 */
098 public static int[] mapping(final int[] array, final int[] indices) {
099
100 if (indices.length > array.length) {
101 throw new IllegalArgumentException("too many indices");
102 }
103
104 final int[] values = new int[indices.length];
105 int i = 0;
106 for (final int index : indices) {
107 values[i++] = array[index];
108 }
109
110 return values;
111 }
112
113 /**
114 * Map the doubles found at given indices.
115 *
116 * @param vals the values to map.
117 * @param indices the indices of objects array.
118 * @return an array of mapped {@code double}s.
119 */
120 public static double[] mapping(final double[] vals, final int[] indices) {
121
122 if (vals == null || vals.length == 0) {
123 return null;
124 }
125
126 if (indices.length > vals.length) {
127 throw new IllegalArgumentException("too many indices");
128 }
129
130 final double[] values = new double[indices.length];
131 int i = 0;
132 for (final int index : indices) {
133 values[i++] = vals[index];
134 }
135
136 return values;
137 }
138
139 /**
140 * Map the values found in the given interval.
141 *
142 * @param vals the values to map.
143 * @param from the first index.
144 * @param to the last index.
145 *
146 * @return an array of {@code double}s.
147 */
148 static public double[] mapping(final double[] vals, int from, int to) {
149 if (vals == null || vals.length == 0) {
150 return null;
151 }
152
153 final double[] values = new double[to - from + 1];
154 int i = 0;
155 for (int index = from; index <= to; index++) {
156 values[i++] = vals[index];
157 }
158
159 return values;
160 }
161
162 /**
163 * Convert objects to ints.
164 *
165 * @param objects the objects to convert.
166 */
167 public static int[] convert2ints(final Object[] objects) {
168 final int[] values = new int[objects.length];
169
170 for (int i = 0; i < objects.length; i++) {
171 values[i] = Integer.parseInt(objects[i].toString());
172 }
173
174 return values;
175 }
176
177 /**
178 * Convert ints to array of Integers.
179 *
180 * @param ints the ints to convert.
181 */
182 public static Integer[] ints2Integers(final int[] ints) {
183 final Integer[] values = new Integer[ints.length];
184
185 for (int i = 0; i < ints.length; i++) {
186 values[i] = new Integer(ints[i]);
187 }
188
189 return values;
190 }
191
192 /**
193 * Convert ints to List of Integers.
194 *
195 * @param ints the ints to convert.
196 */
197 public static List<Integer> asIntList(final int[] ints) {
198 final List<Integer> l = new ArrayList<Integer>();
199
200 for (int i : ints) {
201 l.add(i);
202 }
203
204 return l;
205 }
206
207 /**
208 * Convert arrays of Ts to List of Ts.
209 *
210 * @param os the object array to convert.
211 */
212 public static <T> List<T> asList(final T[] os) {
213 final List<T> l = new ArrayList<T>();
214
215 for (T o : os) {
216 l.add(o);
217 }
218
219 return l;
220 }
221
222 /**
223 * Convert array of doubles to array of Doubles.
224 *
225 * @param dbls the array to convert.
226 */
227 public static Double[] doubles2Doubles(final double[] dbls) {
228 final Double[] values = new Double[dbls.length];
229
230 for (int i = 0; i < dbls.length; i++) {
231 values[i] = new Double(dbls[i]);
232 }
233
234 return values;
235 }
236
237 /**
238 * Sort int values in ascending order.
239 *
240 * @param array the int array to sort.
241 * @return the sorted array.
242 */
243 public static int[] sortUp(final int[] array) {
244 Arrays.sort(array);
245 return array;
246 }
247
248 /**
249 * Sort int values in descending order.
250 *
251 * @param array the int array to sort.
252 * @return the sorted array.
253 */
254 public static int[] sortDown(final int[] array) {
255
256 // ascending sort
257 Arrays.sort(array);
258
259 // put in reverse order
260 final int halfLen = array.length / 2;
261 final int lastIdx = array.length - 1;
262 int temp;
263 for (int i = 0; i < halfLen; i++) {
264 temp = array[i];
265 array[i] = array[lastIdx - i];
266 array[lastIdx - i] = temp;
267 }
268
269 return array;
270 }
271
272 /**
273 * Sort double values in ascending order.
274 *
275 * @param array the double array to sort.
276 * @return the sorted array.
277 */
278 public static double[] sortUp(final double[] array) {
279 Arrays.sort(array);
280 return array;
281 }
282
283 /**
284 * Sort double values in descending order.
285 *
286 * @param array the double array to sort.
287 * @return the sorted array.
288 */
289 public static double[] sortDown(final double[] array) {
290 // ascending sort
291 Arrays.sort(array);
292
293 // reverse
294 final int halfLen = array.length / 2;
295 final int lastIdx = array.length - 1;
296 double temp;
297 for (int i = 0; i < halfLen; i++) {
298 temp = array[i];
299 array[i] = array[lastIdx - i];
300 array[lastIdx - i] = temp;
301 }
302
303 return array;
304 }
305
306 /**
307 * Sort int value indices in ascending order.
308 *
309 * @param array the int array to sort indices.
310 * @return the sorted array.
311 */
312 public static int[] sortIndexesUp(final int[] array) {
313
314 final ArrayIndexComparator idxComp =
315 new AbstractIntsArrayIndexComparator() {
316
317 @Override
318 public int compare(final Integer i1, final Integer i2) {
319 if (getArray()[i1] < getArray()[i2]) {
320 return -1;
321 }
322 if (getArray()[i1] > getArray()[i2]) {
323 return 1;
324 }
325 return 0;
326 }
327 };
328
329 final ArrayIndexSorter sortIndex = new ArrayIndexSorter(array, idxComp);
330
331 return sortIndex.sort();
332 }
333
334 /**
335 * Sort int value indices in descending order.
336 *
337 * @param array the int array to sort indices.
338 * @return the sorted array.
339 */
340 public static int[] sortIndexesDown(final int[] array) {
341
342 final ArrayIndexComparator idxComp =
343 new AbstractIntsArrayIndexComparator() {
344
345 @Override
346 public int compare(final Integer i1, final Integer i2) {
347 return (getArray()[i2] - getArray()[i1]);
348 }
349 };
350
351 final ArrayIndexSorter sortIndex = new ArrayIndexSorter(array, idxComp);
352
353 return sortIndex.sort();
354 }
355
356 public static int[] sortIndexesUp(final double[] array) {
357
358 final ArrayIndexComparator idxComp =
359 new AbstractDoublesArrayIndexComparator() {
360
361 @Override
362 public int compare(final Integer i1, final Integer i2) {
363 if (getArray()[i1] < getArray()[i2]) {
364 return -1;
365 }
366 if (getArray()[i1] > getArray()[i2]) {
367 return 1;
368 }
369 return 0;
370 }
371 };
372
373 final ArrayIndexSorter sortIndex = new ArrayIndexSorter(array, idxComp);
374 return sortIndex.sort();
375 }
376
377 public static int[] sortIndexesDown(final double[] array) {
378
379 final ArrayIndexComparator idxComp =
380 new AbstractDoublesArrayIndexComparator() {
381
382 @Override
383 public int compare(final Integer i1, final Integer i2) {
384 if (getArray()[i1] < getArray()[i2]) {
385 return 1;
386 }
387 if (getArray()[i1] > getArray()[i2]) {
388 return -1;
389 }
390 return 0;
391 }
392 };
393
394 final ArrayIndexSorter sortIndex = new ArrayIndexSorter(array, idxComp);
395 return sortIndex.sort();
396 }
397
398 /**
399 * Merge two sorted arrays (ascending or up) in one
400 *
401 * @param array1 the first sorted array
402 * @param array2 the second sorted array
403 * @return array the sorted merged array
404 */
405 public static double[] mergeUp(final double[] array1, final double[] array2) {
406 final double[] array = new double[array1.length + array2.length];
407 int i = 0;
408 int j = 0;
409 int k = 0;
410
411 // TODO: improve algo with testing mini & maxi values
412
413 while ((i < array1.length) && (j < array2.length)) {
414 if (array1[i] < array2[j]) {
415 array[k] = array1[i];
416 i++;
417 } else {
418 array[k] = array2[j];
419 j++;
420 }
421 k++; // next position in the new array
422 }
423 // Push the remaining elements to the end of new array when a feeder
424 // array is empty
425 while (i < array1.length) {
426 array[k] = array1[i];
427 i++;
428 k++;
429 }
430 while (j < array2.length) {
431 array[k] = array2[j];
432 j++;
433 k++;
434 }
435
436 return array;
437 }
438
439 public static final int[] sortIndices(final double[] objects) {
440 if (objects.length > 0) {
441 final int[] indices = new int[objects.length];
442 for (int i = 0; i < indices.length; i++) {
443 indices[i] = i;
444 }
445 return sortIndices(objects, indices, 0, objects.length - 1);
446 }
447 return null;
448 }
449
450 /**
451 * Reimplementation of quicksort for performance gain.
452 *
453 * @param objects the array of object to sort.
454 * @param from the lower limit.
455 * @param to the upper limit.
456 */
457 public static final int[] sortIndices(final double[] objects,
458 final int[] indices, final int from, final int to) {
459
460 if (from >= to) {
461 return indices;
462 }
463
464 final int pivotIndex = (from + to) / 2;
465 int tmp;
466 int middle = indices[pivotIndex];
467
468 // swap from & middle indices if first value > middle value
469 if (objects[indices[from]] > objects[middle]) {
470 indices[pivotIndex] = indices[from];
471 indices[from] = middle;
472 middle = indices[pivotIndex];
473 }
474
475 // swap peaks[to] & peaks[middle] if last value > middle value
476 if (objects[middle] > objects[indices[to]]) {
477 indices[pivotIndex] = indices[to];
478 indices[to] = middle;
479 middle = indices[pivotIndex];
480
481 // swap peaks[from] & peaks[middle] if first value > middle value
482 if (objects[indices[from]] > objects[middle]) {
483 indices[pivotIndex] = indices[from];
484 indices[from] = middle;
485 middle = indices[pivotIndex];
486 }
487 }
488
489 int left = from + 1;
490 int right = to - 1;
491
492 if (left >= right) {
493 return indices;
494 }
495
496 for (;;) {
497 while (objects[indices[right]] > objects[middle]) {
498 right--;
499 }
500
501 while ((left < right)
502 && (objects[indices[left]] <= objects[middle])) {
503 left++;
504 }
505
506 if (left < right) {
507 tmp = indices[left];
508 indices[left] = indices[right];
509 indices[right] = tmp;
510 right--;
511 } else {
512 break;
513 }
514 }
515
516 sortIndices(objects, indices, from, left);
517 sortIndices(objects, indices, left + 1, to);
518
519 return indices;
520 }
521
522 /**
523 * sort (increasing) the list of arrays based on the values contained in the
524 * first one (think of masses, intensities...)
525 *
526 * @param arrays
527 * @throws IllegalArgumentException if 0 arrays are passed of if length
528 * differs
529 */
530 public static void sortUpArrraysOnFirst(final double[][] arrays) {
531 final int nbArrays = arrays.length;
532 if (nbArrays == 0) {
533 throw new IllegalArgumentException(
534 "cannot pass empty list of arays");
535 }
536
537 final int size = arrays[0].length;
538 final int[] sidx = PrimitiveArrayUtils.sortIndexesUp(arrays[0]);
539 for (int i = 0; i < nbArrays; i++) {
540 if (arrays[i].length != size) {
541 throw new IllegalArgumentException("size of arrays 0 and " + i
542 + " differ : " + size + " vs " + arrays[i]);
543 }
544 final double[] tmp = arrays[i].clone();
545 for (int j = 0; j < tmp.length; j++) {
546 arrays[i][j] = tmp[sidx[j]];
547 }
548 }
549 }
550
551 public static void getNthHighestElement(final double[] array, final int rank) {
552
553 }
554
555 public static double[] floats2doubles(final float[] fArray) {
556 final double[] dArray = new double[fArray.length];
557
558 for (int i = 0; i < fArray.length; i++) {
559 dArray[i] = fArray[i];
560 }
561
562 return dArray;
563 }
564
565 // public static IntegerSequence getIndexRangeWithBinarySearch(
566 // double[] values, final Interval interval) {
567 //
568 // int from = Arrays.binarySearch(values, interval.getLowerBound());
569 // int to = Arrays.binarySearch(values, interval.getUpperBound());
570 //
571 // if (from < 0) {
572 // from = -from - 1;
573 // }
574 // if (to < 0) {
575 // to = -to - 1;
576 // }
577 // return new IntegerSequence.Builder(from, to).build();
578 // }
579
580 // public static int[] getIndexRangeWithBinarySearch(double[] values,
581 // double start, double end) {
582 //
583 // int from = Arrays.binarySearch(values, start);
584 // int to = Arrays.binarySearch(values, end);
585 //
586 // if (from < 0) {
587 // from = -from - 1;
588 // }
589 // if (to < 0) {
590 // to = -to - 1;
591 // }
592 // return new int[] {from, to};
593 // }
594
595 /**
596 * Get the index range of {@code values} where each is contained in the
597 * given interval.
598 *
599 * @param values the values to get the range from.
600 * @param start the interval included start.
601 * @param end the interval excluded end.
602 * @return a range of indices
603 */
604 public static int[] getIndexRange(double[] values, double start, double end) {
605 IntegerSequence seq =
606 getIndexRange(values, new Interval.Builder(start, end).build());
607
608 if (seq.isEmpty()) {
609 return new int[] { };
610 } else {
611 return new int[] {seq.getFrom(), seq.getTo() - 1};
612 }
613 }
614
615 /**
616 * Get an interval of index in sorted values.
617 *
618 * @param interval of definition.
619 *
620 * @return an interval on values index [imin, imax[.
621 *
622 * @throws IllegalArgumentException if values are not sorted.
623 */
624 public static IntegerSequence getIndexRange(double[] values,
625 final Interval interval) {
626
627 int imin = -1;
628 int imax = -1;
629
630 // throw IllegalArgumentException if not sorted !
631 MathUtils.checkOrder(values, 1, false);
632
633 double lowerBound = interval.getLowerBound();
634 double upperBound = interval.getUpperBound();
635
636 for (int index = 0; index < values.length; index++) {
637
638 if (values[index] < lowerBound
639 || (values[index] == lowerBound && !interval
640 .isLowerBoundIncluded())) {
641 imin = index + 1;
642 continue;
643 }
644
645 // greater than lower bound
646 if (values[index] < upperBound
647 || (values[index] == upperBound && interval
648 .isUpperBoundIncluded())) {
649 imax = index;
650 } else {
651 break;
652 }
653 }
654
655 if (imax == -1) {
656 return IntegerSequence.emptyInstance();
657 }
658
659 if (imin == -1) {
660 imin = 0;
661 }
662
663 return new IntegerSequence.Builder(imin, imax + 1).build();
664 }
665
666 /**
667 * Search the given query intervals into the target values.
668 *
669 * @param values the sorted values to find indices in.
670 * @param intervalCenters the sorted interval centers query.
671 * @param halfIntervalRange the half-range interval for all query value.
672 *
673 * @return a list of indices found in at least one query interval.
674 *
675 * @throws IllegalArgumentException - if the arrays are not sorted.
676 */
677 public static List<Integer> searchIndices(double[] values,
678 double[] intervalCenters, double halfIntervalRange) {
679
680 return searchIndices(values, intervalCenters, halfIntervalRange, 0);
681 }
682
683 /**
684 * Search the given query intervals into the target values.
685 *
686 * @param values the sorted values to find indices in.
687 * @param intervalCenters the sorted interval centers query.
688 * @param halfIntervalRange the half-range interval for all query value.
689 * @param from the begin index to search into values.
690 *
691 * @return a list of indices found in at least one query interval.
692 *
693 * @throws IllegalArgumentException - if the arrays are not sorted.
694 */
695 public static List<Integer> searchIndices(double[] values,
696 double[] intervalCenters, double halfIntervalRange, int from) {
697
698 MathUtils.checkOrder(values, 1, false);
699 MathUtils.checkOrder(intervalCenters, 1, false);
700
701 final List<Integer> indices = new ArrayList<Integer>();
702
703 int intervalIndex = 0;
704
705 int i = from;
706
707 while (i < values.length && intervalIndex < intervalCenters.length) {
708
709 // get the index in values <= lower bound of current interval i
710 i =
711 Arrays.binarySearch(values, i, values.length,
712 intervalCenters[intervalIndex] - halfIntervalRange);
713
714 // if lower bound was not found -> compute the insertion point
715 if (i < 0) {
716 i = -i - 1;
717 }
718
719 // values[i] >= current lower bound
720 while (i < values.length
721 && values[i] <= intervalCenters[intervalIndex]
722 + halfIntervalRange) {
723
724 indices.add(i++);
725 }
726
727 // next interval
728 intervalIndex++;
729 }
730
731 return indices;
732 }
733
734 public static double[] getSubArray(double[] values, int from, int to) {
735 return Arrays.copyOfRange(values, from, to);
736 }
737
738 /**
739 * Convert an integer to an array of bytes.
740 *
741 * http://snippets.dzone.com/posts/show/93
742 *
743 * @param value the integer to convert.
744 */
745 public static final byte[] intToByteArray(int value) {
746 return new byte[] {(byte) (value >>> 24), (byte) (value >>> 16),
747 (byte) (value >>> 8), (byte) value};
748 }
749
750 /**
751 * Convert an array of bytes into integer value.
752 *
753 * http://snippets.dzone.com/posts/show/93
754 *
755 * @param bytes the bytes to convert into integer.
756 */
757 public static final int byteArrayToInt(byte[] bytes) {
758 return (bytes[0] << 24) + ((bytes[1] & 0xFF) << 16)
759 + ((bytes[2] & 0xFF) << 8) + (bytes[3] & 0xFF);
760 }
761
762 /**
763 * Convert a list of {@code Double}s to an array of doubles.
764 *
765 * @param list the list to convert.
766 * @return an array of doubles.
767 */
768 public static final double[] toDoubleArray(List<Double> list) {
769 final double[] array = new double[list.size()];
770
771 for (int i = 0; i < array.length; i++) {
772 array[i] = list.get(i).doubleValue();
773 }
774 return array;
775 }
776
777 /**
778 * Convert a list of {@code Integer}s to an array of ints.
779 *
780 * @param list the list to convert.
781 * @return an array of ints.
782 */
783 public static final int[] toIntArray(List<Integer> list) {
784 final int[] array = new int[list.size()];
785
786 for (int i = 0; i < array.length; i++) {
787 array[i] = list.get(i).intValue();
788 }
789 return array;
790 }
791
792 /**
793 * Copy array of doubles accessible from {@code T-object} in a given {@code
794 * copy} array.
795 *
796 * @param <T> the object typed wrapping double[].
797 * @param object the {@code T-object} to copy doubles from.
798 * @param copy the array to copy doubles into.
799 * @param o2a the transformer to access double[] from {@code T-object}.
800 *
801 * @return the given {@code copy} loaded with doubles or a new array if
802 * {@code copy} is not defined or had reduced capacity.
803 */
804 public static <T> double[] loadArray(T object,
805 Transformer<T, double[]> o2a, double[] copy) {
806 double[] array = o2a.transform(object);
807
808 if (copy == null || copy.length < array.length) {
809 copy = new double[array.length];
810 }
811 System.arraycopy(array, 0, copy, 0, array.length);
812
813 return copy;
814 }
815 }