Способ, которым я решил это, разделял проблему на 2 общих случая, каждый с 2 вариантами.Общие случаи:
1.Перестановки без повторений.
[ Eli , Dex , Eva ]
[ 1 , 2 , 3 ]
[ 1 , 3 , 2 ]
[ 2 , 1 , 3 ]
[ 2 , 3 , 1 ]
[ 3 , 1 , 2 ]
[ 3 , 2 , 1 ]
2.Перестановки с повторениями.
[ Eli , Dex , Eva ]
[ 1 , 1 , 1 ]
[ 1 , 1 , 2 ]
[ 1 , 2 , 1 ]
[ 2 , 1 , 1 ]
[ 2 , 2 , 1 ]
[ 2 , 1 , 2 ]
[ 1 , 2 , 2 ]
Я решил представить null
значения с 0
, поэтому возможны следующие варианты:
1.1.Перестановки без повторений, но со значениями null
.
[ Eli , Dex , Eva ]
[ 0 , 1 , 2 ]
[ 0 , 2 , 1 ]
[ 1 , 0 , 2 ]
[ 1 , 2 , 0 ]
[ 2 , 0 , 1 ]
[ 2 , 1 , 0 ]
2.1.Перестановки с повторениями и значениями null
.
[ Eli , Dex , Eva ]
[ 0 , 0 , 0 ]
[ 0 , 0 , 1 ]
[ 0 , 1 , 0 ]
[ 1 , 0 , 0 ]
[ 1 , 1 , 0 ]
[ 1 , 0 , 1 ]
[ 0 , 1 , 1 ]
После генерации приведенных выше числовых представлений отображение данных с датами сводится к замене чисел строками даты, а нулей - нулями.
Класс Combinatorics.java вычисляет то, что я называю «моделью прецедентности», выполняя перестановки в массивах.Запустите метод main
этого класса, чтобы сгенерировать числовое представление дат на основе приоритета, которое можно преобразовать в даты на основе простых жестко заданных или динамически генерируемых значений.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class Combinatorics {
PrecedenceModel precedenceModel;
public Combinatorics(int elementCount) {
this.precedenceModel = new PrecedenceModel(elementCount);
}
public PrecedenceModel getPrecedenceModel() {
return precedenceModel;
}
/**
* Calculates all permutations of elements given in <b>{@code array}</b> recursively
*/
public static void permute(int[] array, int nestingLevel, Set<List<Integer>> results, Predicate<int[]> filter){
if (nestingLevel == array.length) {
if(filter.test(array)) {
results.add(Arrays.stream(array).boxed().collect(Collectors.toCollection(ArrayList::new)));
}
return;
}
permute(array, nestingLevel + 1, results, filter);
for (int index = nestingLevel + 1; index < array.length; index++) {
if (array[index] == array[nestingLevel]) {
continue;
}
array = array.clone();
int temp = array[index];
array[index] = array[nestingLevel];
array[nestingLevel] = temp;
permute(array, nestingLevel + 1, results, filter);
}
}
/**
* Calculates all permutations of elements given in <b>{@code array}</b> recursively
*/
public Set<List<Integer>> getPermutations(int[] array, Predicate<int[]> filter){
Set<List<Integer>> results = new LinkedHashSet<>();
permute(array, 0, results, filter);
return results;
}
/**
* Calculates all permutations with repeated values based on
* the base matrix of the precedence model's matrices
*/
public Set<List<Integer>> getPermutationsWithRepetitions(int[][] precedenceModelMatrix, Predicate<int[]> filter){
Set<List<Integer>> permutationsWithRepetitions = new LinkedHashSet<>();
if(filter.test(precedenceModelMatrix[precedenceModelMatrix.length - 1])) {
permutationsWithRepetitions.add(
Arrays.stream(precedenceModelMatrix[precedenceModelMatrix.length - 1])
.boxed().collect(Collectors.toCollection(ArrayList::new)));
}
for (int i = 1; i < (precedenceModelMatrix.length - 1); i++) {
for (int j = i + 1; j < precedenceModelMatrix.length; j++) {
int array[] = precedenceModelMatrix[i].clone();
permutationsWithRepetitions.addAll(getPermutations(array, filter));
for (int k = 0; k < i + 1; k++) {
array[k] = j - i + precedenceModelMatrix[0][0];
}
array[j] = precedenceModelMatrix[0][0];
permutationsWithRepetitions.addAll(getPermutations(array, filter));
}
}
return permutationsWithRepetitions;
}
private Set<List<Integer>> getPrecedenceModel(PermutationType ... permutationTypes){
return getPrecedenceModel((a -> true), permutationTypes);
}
public Set<List<Integer>> getPrecedenceModel(PermutationType permutationTypes, Predicate<int[]> filter){
return getPrecedenceModel(filter, permutationTypes);
}
private Set<List<Integer>> getPrecedenceModel(Predicate<int[]> filter, PermutationType ... permutationTypes){
Set<List<Integer>> result = new LinkedHashSet<>();
Set<PermutationType> permTypes = new LinkedHashSet<>(Arrays.asList(permutationTypes));
System.out.println(permTypes);
Set<List<Integer>> simplePermutations = null;
Set<List<Integer>> permutationsWithRepetitions = null;
Set<List<Integer>> permutationsWithSingleParameter = null;
Set<List<Integer>> permutationsWithParameterRepetitions = null;
if(permTypes.contains(PermutationType.ALL_PERMUTATIONS)) {
simplePermutations = getPermutations(getPrecedenceModel().getBaseMatrix()[0], filter);
permutationsWithRepetitions = getPermutationsWithRepetitions(getPrecedenceModel().getBaseMatrix(), filter);
permutationsWithParameterRepetitions = getPermutationsWithRepetitions(getPrecedenceModel().getParameterMatrix(), filter);
permutationsWithSingleParameter = getPermutations(getPrecedenceModel().getParameterMatrix()[0], filter);
result.addAll(simplePermutations);
result.addAll(permutationsWithRepetitions);
result.addAll(permutationsWithParameterRepetitions);
result.addAll(permutationsWithSingleParameter);
return result;
}
if(permTypes.contains(PermutationType.SIMPLE_PERMUTATIONS)) {
simplePermutations = getPermutations(getPrecedenceModel().getBaseMatrix()[0], filter);
result.addAll(simplePermutations);
}
if(permTypes.contains(PermutationType.PERMUTATION_WITH_REPETITIONS)) {
permutationsWithRepetitions = getPermutationsWithRepetitions(getPrecedenceModel().getBaseMatrix(), filter);
result.addAll(permutationsWithRepetitions);
}
if(permTypes.contains(PermutationType.PERMUTATION_WITH_PARAMETER_REPETITIONS)) {
permutationsWithParameterRepetitions = getPermutationsWithRepetitions(getPrecedenceModel().getParameterMatrix(), filter);
result.addAll(permutationsWithParameterRepetitions);
}
if(permTypes.contains(PermutationType.PERMUTATION_WITH_SINGLE_PARAMETER)) {
permutationsWithSingleParameter = getPermutations(getPrecedenceModel().getParameterMatrix()[0], filter);
result.addAll(permutationsWithSingleParameter);
}
return result;
}
public static void main(String[] args){
Combinatorics combinatorics = new Combinatorics(3);
// Set<List<Integer>> precedenceModelBypass = combinatorics.getPermutations(new int[] {1,2,3}, (a -> true));
// System.out.println(ApiUtils.collectionToStringN1Dn(precedenceModelBypass));
Set<List<Integer>> precedenceModel = combinatorics.getPrecedenceModel(
// PermutationType.ALL_PERMUTATIONS//3(6)
// ,
PermutationType.SIMPLE_PERMUTATIONS//3(6)
,
PermutationType.PERMUTATION_WITH_REPETITIONS//3(7)
// ,
// PermutationType.PERMUTATION_WITH_PARAMETER_REPETITIONS//3(7)
// ,
// PermutationType.PERMUTATION_WITH_SINGLE_PARAMETER//3(6)
);
System.out.println(org.apache.commons.lang3.StringUtils.repeat('-', 200));
System.out.println("Numeric Model. Count: " + precedenceModel.size());
System.out.println(ApiUtils.collectionToStringN1Dn(precedenceModel));
}
}
Класс PrecedenceModel.java генерирует пару квадратных матриц на основе количества элементов, которые будут использоваться для расчета премутаций.
import java.util.LinkedHashMap;
import java.util.Map;
public class PrecedenceModel {
private int elementCount;
private int[][] baseMatrix;
private int[][] parameterMatrix;
public PrecedenceModel(int elementCount) {
this.elementCount = elementCount;
setBaseMatrix(elementCount);
setParameterMatrix(elementCount);
}
public int getElementCount() {
return elementCount;
}
public int[][] getBaseMatrix() {
return baseMatrix;
}
public void setBaseMatrix(int elementCount) {
baseMatrix = new int[elementCount][elementCount];
for (int i = 0; i < elementCount; i++) {
for (int j = 0; j < elementCount; j++) {
baseMatrix[i][j] = (j <= i) ? 1 : j + 1 - i;
}
}
}
public int[][] getParameterMatrix() {
return parameterMatrix;
}
public void setParameterMatrix(int elementCount) {
parameterMatrix = new int[elementCount][elementCount];
for (int i = 0; i < elementCount; i++) {
for (int j = 0; j < elementCount; j++) {
parameterMatrix[i][j] = (j <= i) ? 0 : j - i;
}
}
}
@SafeVarargs
public static <T> Map<T, Integer> toMap(T ... values) {
Map<T, Integer> map = new LinkedHashMap<>(values.length);
for (int i = 0; i < values.length; i++) {
map.put(values[i], i);
}
return map;
}
}
Класс PermutationType.java будетиспользоваться для классификации различных перестановок, которые мы можем получить.Его атрибут isParameterRequired
будет указывать, есть ли в матрице нули, которые я считаю значениями параметра, потому что мы можем заменить их значениями null
или любыми другими значениями позже.
public enum PermutationType {
SIMPLE_PERMUTATIONS (false),
PERMUTATION_WITH_SINGLE_PARAMETER (true),
PERMUTATION_WITH_PARAMETER_REPETITIONS (true),
PERMUTATION_WITH_REPETITIONS (false),
ALL_PERMUTATIONS (true);
private boolean isParameterRequired;
private PermutationType(boolean isParameterRequired) {
this.isParameterRequired = isParameterRequired;
}
public boolean isParameterRequired() {
return isParameterRequired;
}
}
Вот немногобольше о классе PrecedenceModel.java .2 матрицы baseMatrix
и parameterMatrix
, сгенерированные этим классом, будут выглядеть следующим образом:
baseMatrix
[1, 2, 3, 4]
[1, 1, 2, 3]
[1, 1, 1, 2]
[1, 1, 1, 1]
parameterMatrix
[0, 1, 2, 3]
[0, 0, 1, 2]
[0, 0, 0, 1]
[0, 0, 0, 0]
baseMatrix
будет использоваться для вычисления числового представления дат без null
значений (или параметров).parameterMatrix
будет использоваться для вычисления числового представления дат с null
значениями (или параметрами).
Первая строка любой матрицы используется для вычисления всех перестановок без повторений .
Приближается сложная часть ...
Вторые и последние строки используются для расчета перестановок только с повторениями .Значения каждой из этих строк будут переставлены для создания определенных приоритетов, и каждый из этих результатов будет переставлен, чтобы получить окончательный результат всех возможных перестановок с повторениями.Например, давайте возьмем строку 2nd baseMatrix
:
[1, 1, 2, 3] <- contains 2 repeated values
Чтобы получить различные приоритеты этого ряда, я перемешиваю приоритет повторяющихся элементов (1,1) с каждымиз неповторяющихся.Это может быть сделано путем сдвига значений, таких как:
>>>>>>>
^ ^ v
^ ^ v
[1, 1, 2, 3] <- contains 2 repeated values
^ ^ v
^ ^ v
<<<<<<<
Различные приоритеты для 2-й строки baseMatrix
:
[1, 1, 2, 3]
[2, 2, 1, 3]
[1, 1, 2, 3]
[3, 3, 2, 1]
Тогда все перестановкииз всех различных приоритетов для 2-й строки должны быть рассчитаны.
Для завершения, все вышеупомянутые процедуры для 2-го должны применяться для 3-го ряд также.И так как 4-ая строка (граничный регистр) содержит все повторяющиеся элементы, с ней не нужно запускать никаких операций.
Следующий класс бонусов является лишь примером процесса, который я использую для вычислениябазовая матрица и различный приоритет для каждой строки в матрице.
import java.util.Arrays;
public class RationaleForRepetitions {
private class PrecedenceModel {
private int elementCount;
private int[][] baseMatrix;
public PrecedenceModel(int elementCount) {
this.elementCount = elementCount;
setBaseMatrix(elementCount);
}
public int getElementCount() {
return elementCount;
}
public int[][] getBaseMatrix() {
return baseMatrix;
}
public void setBaseMatrix(int elementCount) {
baseMatrix = new int[elementCount][elementCount];
for (int i = 0; i < elementCount; i++) {
for (int j = 0; j < elementCount; j++) {
baseMatrix[i][j] = (j <= i) ? 1 : j + 1 - i;
}
}
}
}
public static void main(String[] args) {
final int numberOfElements = 8;
PrecedenceModel precedenceModel = new RationaleForRepetitions().new PrecedenceModel(numberOfElements);
System.out.println("Number of elements to calculate = " + precedenceModel.getElementCount() + System.lineSeparator());
System.out.println("Precedence Model: ");
for (int i = 0; i < precedenceModel.getElementCount(); i++) {
System.out.println(Arrays.toString(precedenceModel.getBaseMatrix()[i]));
}
System.out.println(System.lineSeparator() + "Discard first and last rows (boundary cases). First row has no repetitions and last one is all repetitions." + System.lineSeparator());
System.out.println("i -> j");
for (int i = 1; i < (precedenceModel.getElementCount() - 1); i++) {
System.out.print(i + " -> ");
for (int j = i + 1; j < precedenceModel.getElementCount(); j++) {
System.out.print(j - i + 1 + " ");
}
System.out.println();
}
System.out.println(System.lineSeparator());
System.out.println("Permutations should run on each of the following results:" + System.lineSeparator());
for (int i = 1; i < (precedenceModel.getElementCount() - 1); i++) {
for (int j = i + 1; j < precedenceModel.getElementCount(); j++) {
int array[] = precedenceModel.getBaseMatrix()[i].clone();
System.out.println(Arrays.toString(array));
for (int k = 0; k < i + 1; k++) {
array[k] = j - i + 1;
}
array[j] = 1;
System.out.println(String.format("%s%s", Arrays.toString(array), System.lineSeparator()));
}
System.out.println(String.format("%2$s%2$s%2$s%1$s", System.lineSeparator(), "-------------------"));
}
System.out.println("Precedence Model: ");
for (int i = 0; i < precedenceModel.getElementCount(); i++) {
System.out.println(Arrays.toString(precedenceModel.getBaseMatrix()[i]));
}
}
}
Следующий код только для правильного отображения / печати результатов , и его можно опустить, если ссылки из класса Combinatoricsудалены.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
public class ApiUtils {
public static Map<String, String> mergeMapsWithPrecedence(Map<String, String> ... higherToLowerPrecedenceMaps) {
int mapLength = 0;
for (Map<String, String> map : higherToLowerPrecedenceMaps) {
// mapLength += map.size();
mapLength = map.size() > mapLength ? map.size() : mapLength;
}
Map<String, String> superMap = new HashMap<>(mapLength);
for (Map<String, String> map : higherToLowerPrecedenceMaps) {
map.forEach((k,v) -> {
if( ! superMap.containsKey(k) ) {
superMap.put(k, v);
}
});
}
return superMap;
}
public static <T> Map<Integer, T> getMap(T ... values) {
Map<Integer, T> map = new HashMap<>(values.length);
for (int i = 0; i < values.length; i++) {
map.put(i, values[i]);
}
return map;
}
public static <T> List<T> getList(T ... values) {
return new ArrayList<>(Arrays.asList(values));
}
public static void appendNewLine(StringBuffer stringBuffer, String content) {
stringBuffer
.append(content)
.append(System.lineSeparator());
}
public static void appendKeyValueNewLine(StringBuffer stringBuffer, String key, String value, String delimiter) {
stringBuffer
.append(key)
.append(delimiter)
.append(value)
.append(System.lineSeparator());
}
public static List<String> replaceParameterizedList(List<String> data) {
return
data
.stream()
.filter(s -> ! ApiConstantsUtils.MISSING.equals(s))
.map(s -> ApiConstantsUtils.NULL.equals(s) ? null : s)
.collect(Collectors.toList());
}
public static Map<String, String> replaceParameterizedMap(Map<String, String> data) {
Map<String, String> updatedData = new HashMap<>();
for (Entry<String, String> element : data.entrySet()) {
if (ApiConstantsUtils.NULL.equals(element.getValue())) {
updatedData.put(element.getKey(), null);
} else if ( ! ApiConstantsUtils.MISSING.equals(element.getValue()) ) {
updatedData.put(element.getKey(), element.getValue());
}
}
return updatedData;
}
public static List<Map<String, String>> replaceParameterizedListOfMaps(List<Map<String, String>> data) {
return
data
.stream()
.map(map -> replaceParameterizedMap(map))
.collect(Collectors.toList());
}
/**
* Naming conventions for methods that print nested collections:
*
* Nx = (N)esting, x = level
* Sn = (D)elimiter. n = newLine
*/
public static <T extends Collection<?>> String collectionToStringN1Dn(Collection<T> collection) {
return
collection
.stream()
.map(list -> list.toString())
.collect(Collectors.joining(System.lineSeparator()));
}
public static void printStackTrace() {
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
System.out.println(ste.toString());
}
}
public static void creatFileInRoot(String fileContent) {
creatFileInRoot(Arrays.asList(fileContent), "txt");
}
public static void creatFileInRoot(Iterable<String> fileContent) {
creatFileInRoot(fileContent, "txt");
}
public static void creatFileInRoot(Iterable<String> fileContent, String extension) {
Path outputPath = ApiConstantsUtils.OUTPUT_FOLDER;
if(extension == null || StringUtils.isBlank(extension)) {
extension = "txt";
}
String filename =
ApiReflectionUtils.getCallerCallerClassName().getSimpleName() +
"_" + Instant.now().toEpochMilli() +
"." + extension;
filename = filename.replaceAll(" ", "_");
creatFileInRoot(outputPath, filename, fileContent);
}
private static void creatFileInRoot(Path outputPath, String filename, Iterable<String> fileContent) {
outputPath.toFile().mkdirs();
try {
Files.write(outputPath.resolve(filename), fileContent, StandardOpenOption.CREATE_NEW);
System.out.println("File created: " + outputPath.resolve(filename).toAbsolutePath().toString());
} catch (IOException e) {
e.printStackTrace();
System.out.println("Error while attempting to create file: " + outputPath.resolve(filename).toAbsolutePath().toString());
}
}
}
public class ApiReflectionUtils {
public static Class<?> getCallerClassName() {
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
for (int i = 1; i < stElements.length; i++) {
StackTraceElement ste = stElements[i];
if (!ste.getClassName().equals(ApiReflectionUtils.class.getName())
&& ste.getClassName().indexOf("java.lang.Thread") != 0) {
try {
return Class.forName(ste.getClassName());
} catch (ClassNotFoundException e) {}
}
}
return null;
}
public static Class<?> getCallerCallerClassName() {
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
String callerClassName = null;
for (int i = 1; i < stElements.length; i++) {
StackTraceElement ste = stElements[i];
if (!ste.getClassName().equals(ApiReflectionUtils.class.getName())
&& ste.getClassName().indexOf("java.lang.Thread") != 0) {
if (callerClassName == null) {
callerClassName = ste.getClassName();
} else if (!callerClassName.equals(ste.getClassName())) {
try {
return Class.forName(ste.getClassName());
} catch (ClassNotFoundException e) {}
}
}
}
return null;
}
}
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ApiConstantsUtils {
public static final String CALCULATE = "calculate";
public static final String NULL = "[NULL]";
public static final String MISSING = "[MISSING]";
public static final Path OUTPUT_FOLDER = Paths.get("src/main/resources/output");
public enum ComparisonCardinality{
ONE_TO_ONE,
ONE_TO_MANY,
MANY_TO_ONE,
MANY_TO_MANY;
public static ComparisonCardinality getElementComparisonCardinality(List<?> objectsLeft, List<?> objectsRight) {
if (objectsLeft.size() == 1 && objectsRight.size() == 1) {
return ONE_TO_ONE;
} else if (objectsLeft.size() == 1 && objectsRight.size() > 1) {
return ONE_TO_MANY;
} else if (objectsLeft.size() > 1 && objectsRight.size() == 1) {
return MANY_TO_ONE;
} else if (objectsLeft.size() > 1 && objectsRight.size() == objectsLeft.size()) {
return MANY_TO_MANY;
}
return null;
}
}
public enum ComparisonOperator{
EQUAL_TO("=", "equal"),
DISTINCT_FROM("<>", "distinct"),
GREATER_THAN(">", "greater"),
LESS_THAN("<", "less");
private String operator;
private String keyWord;
ComparisonOperator(String operator, String keyWord) {
this.operator = operator;
this.keyWord = keyWord;
}
public String getOperator() {
return operator;
}
public String getKeyWord() {
return keyWord;
}
private static Map<String,ComparisonOperator> enumValues = new HashMap<>();
static {
for (ComparisonOperator comparisonOperator : ComparisonOperator.values()) {
enumValues.put(comparisonOperator.keyWord, comparisonOperator);
}
}
public static ComparisonOperator getByKeyWord(String operatorKeyWord) {
return enumValues.get(operatorKeyWord);
}
}
}