/** * Copyright 2014 Google Inc. All rights reserved. * <p> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.formulasearchengine.mathosphere.mathpd; import com.formulasearchengine.mathosphere.mathpd.pojos.ExtractedMathPDDocument; import org.apache.flink.api.java.tuple.Tuple2; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.*; public class CollectionUtils { /** * Convert the list of lists into a single list */ public static <T> List<T> concatenate(List<List<T>> lists) { List<T> result = new ArrayList<T>(); for (List<T> list : lists) { result.addAll(list); } return result; } /** * Partition a list into <code>num</code> sub-lists. If the list does * not divide evenly, the extra 'n' elements are split across the * first 'n' lists. There will be no more lists than elements returned (i.e. no empty lists tacked on to the end) */ public static <T> List<List<T>> partition(List<T> list, int num) { if (num < 1) { throw new IllegalArgumentException("Number of sub-lists must be greater than zero"); } List<List<T>> result = new ArrayList<List<T>>(); int index = 0; int listsRemaining = num; int elementsRemaining = list.size(); while (elementsRemaining > 0) { int size = (int) Math.ceil(elementsRemaining / (listsRemaining + 0.0)); List<T> subList = list.subList(index, index + size); result.add(subList); listsRemaining--; elementsRemaining -= size; index += size; } if (elementsRemaining != 0) { throw new IllegalStateException(String.format("Loop exited with %d elements still remaining", elementsRemaining)); } return result; } /** * Partition a list into sub-lists with <code>size</code> elements * each. If the list does not divide evenly, the extra elements are * all in the final list. */ public static <T> List<List<T>> partitionBySize(List<T> list, int size) { if (size < 1) { throw new IllegalArgumentException("Size of sub-lists must be greater than zero"); } List<List<T>> result = new ArrayList<List<T>>(); int index = 0; int elementsRemaining = list.size(); while (elementsRemaining > 0) { int listSize = Math.min(elementsRemaining, size); List<T> subList = list.subList(index, index + listSize); result.add(subList); elementsRemaining -= listSize; index += listSize; } if (elementsRemaining != 0) { throw new IllegalStateException(String.format("Loop exited with %d elements still remaining", elementsRemaining)); } return result; } public static List<List<Tuple2<String, ExtractedMathPDDocument>>> overlapInPercent(List<List<Tuple2<String, ExtractedMathPDDocument>>> partitions, double before, double after) { double allElements = 0.0; for (List<Tuple2<String, ExtractedMathPDDocument>> partition : partitions) { allElements += partition.size(); } int beforeAbs = (int) (allElements * before); int afterAbs = (int) (allElements * after); return overlap(partitions, beforeAbs, afterAbs); } /** * Introduces overlap into a series of lists. * * @param before # of elements from the end of the previous list to prepend * @param after # of elements from the beginning of the next list to append */ public static <T> List<List<T>> overlap(List<List<T>> lists, int before, int after) { if (before < 0) { throw new IllegalArgumentException("Value of before cannot be negative"); } if (after < 0) { throw new IllegalArgumentException("Value of after cannot be negative"); } System.out.println("got " + lists.size() + " lists that will be overlapped now"); ListIterator<List<T>> iter = lists.listIterator(); List<List<T>> result = new ArrayList<List<T>>(); for (; iter.hasNext(); ) { List<T> current = new ArrayList<T>(iter.next()); List<T> prev = before > 0 ? findPrevious(iter) : null; List<T> next = after > 0 ? findNext(iter) : null; System.out.println("cur list has " + current.size() + " entries"); if (prev != null) { int prefBeforeSize = Math.min(before, prev.size()); List<T> overlap = prev.subList(prev.size() - prefBeforeSize, prev.size()); current.addAll(0, overlap); } if (next != null) { int nextAfterSize = Math.min(after, next.size()); List<T> overlap = next.subList(0, nextAfterSize); current.addAll(overlap); } result.add(current); } return result; } private static <T> T findPrevious(ListIterator<T> iter) { T prev = null; iter.previous(); // rewind if (iter.hasPrevious()) { prev = iter.previous(); iter.next(); // come back } iter.next(); // come back return prev; } private static <T> T findNext(ListIterator<T> iter) { T next = null; if (iter.hasNext()) { next = iter.next(); iter.previous(); // come back } return next; } public static Properties toProperties(Iterable<Map.Entry<String, String>> propSrc) { Properties props = new Properties(); for (Map.Entry<String, String> entry : propSrc) { String name = entry.getKey(); String val = entry.getValue(); props.setProperty(name, val); } return props; } public static Map<String, String> toMap(Properties props) { return new HashMap(props); } // only captures adds and mods, not deletes public static Properties extractChanges(Properties start, Properties end) { Properties diff = new Properties(); for (String name : end.stringPropertyNames()) { if (start.getProperty(name) == null || !start.getProperty(name).equals(end.getProperty(name))) { diff.setProperty(name, end.getProperty(name)); } } return diff; } /** * Returns new properties with <code>String.trim()</code> applied to every property value. The original properties are unchanged. */ public static Properties toTrimmedProperties(Properties props) { Properties trimmed = new Properties(); for (String name : props.stringPropertyNames()) { String val = props.getProperty(name); val = val == null ? val : val.trim(); trimmed.setProperty(name, val); } return trimmed; } /** * Converts properties to file storage format */ public static String toFileContent(Properties props) { try { StringWriter writer = new StringWriter(); props.store(writer, ""); return writer.toString(); } catch (IOException ioe) { throw new IllegalStateException(ioe); // shouldn't happen } } /** * Converts properties from file storage format */ public static Properties fromFileContent(String content) { try { StringReader reader = new StringReader(content); Properties props = new Properties(); props.load(reader); return props; } catch (IOException ioe) { throw new IllegalStateException(ioe); // shouldn't happen } } public static void clearProperties(Properties props, Collection<String> names) { props.keySet().removeAll(names); } }