Nano Hash - криптовалюты, майнинг, программирование

Как составить комбинацию из значений LinkedHashMap‹String, ArrayList‹ArrayList››

Предположим, у нас есть внизу LinkedHashMap‹String, ArrayList‹ArrayList››

    {FRA=[[1, 2], [3, 4]], MEL=[[5, 6]]}

Результат должен быть

    [1,2,5,6], [3,4,5,6]

Аналогично, если ввод:

    {SFO=[[1]], SEA=[[2], [3], [4]], PHX=[[5], [6]]}

Тогда ожидаемый результат

    [1,2,5],[1,2,6],[1,3,5],[1,3,6],[1,4,5],[1,4,6]

Я пробовал код ниже, но не получил ожидаемого результата.

    public static ArrayList<List<String>> getCombinations(ArrayList<ArrayList<String>> valueSetList) {
    int comboCount = 1;
    for (List<String> valueSet : valueSetList)
        comboCount = Math.multiplyExact(comboCount, valueSet.size()); // Fail if overflow
    ArrayList<List<String>> combinations = new ArrayList<>(comboCount);
    for (int comboNumber = 0; comboNumber < comboCount; comboNumber++) {
        List<String> combination = new ArrayList<>(valueSetList.size());
        int remain = comboNumber;
        for (List<String> valueSet : valueSetList) {
            combination.add(valueSet.get(remain % valueSet.size()));
            
            remain /= valueSet.size();
        }
        combinations.add(combination);
    }
    return combinations;
}

Любая помощь высоко ценится.

25.10.2020


Ответы:


1

Следующее рекурсивное решение основано на ответе Филиппа Мейстера на аналогичный вопрос о построении Декартово произведение:

static List<List<Integer>> merge(List<List<List<Integer>>> lists) {
    List<List<Integer>> resultLists = new ArrayList<>();
    if (lists.size() == 0) {
        resultLists.add(new ArrayList<>());
    } else {
        List<List<Integer>> firstList = lists.get(0);
        List<List<Integer>> remainingLists = merge(lists.subList(1, lists.size()));
        for (List<Integer> first : firstList) {
            for (List<Integer> remaining : remainingLists) {
                List<Integer> resultList = new ArrayList<>();
                resultList.addAll(first);
                resultList.addAll(remaining);
                resultLists.add(resultList);
            }
        }
    }
    return resultLists;
}  

Основное отличие заключается в типе возврата и добавлении всех элементов списка first во вложенный список в соответствии с требованиями.

Тестовая настройка

private static void testCombinations(Map<String, List<List<Integer>>> map) {
    System.out.println("input map: " + map);
    
    List<List<Integer>> list = merge(new ArrayList<>(map.values()));
    
    list.forEach(System.out::println);
}

// --------
Map<String, List<List<Integer>>> map1 = new LinkedHashMap<>();

map1.put("SFO", Arrays.asList(Arrays.asList(1)));
map1.put("SEA", Arrays.asList(Arrays.asList(2), Arrays.asList(3), Arrays.asList(4)));
map1.put("PHX", Arrays.asList(Arrays.asList(5), Arrays.asList(6)));

testCombinations(map1);
        
Map<String, List<List<Integer>>> map2 = new LinkedHashMap<>();

map2.put("FRA", Arrays.asList(Arrays.asList(1, 2), Arrays.asList(3, 4)));
map2.put("MEL", Arrays.asList(Arrays.asList(5, 6)));
testCombinations(map2);

Вывод:

input map: {SFO=[[1]], SEA=[[2], [3], [4]], PHX=[[5], [6]]}
[1, 2, 5]
[1, 2, 6]
[1, 3, 5]
[1, 3, 6]
[1, 4, 5]
[1, 4, 6]
input map: {FRA=[[1, 2], [3, 4]], MEL=[[5, 6]]}
[1, 2, 5, 6]
[3, 4, 5, 6]

Решение может быть реализовано с использованием потоков и рекурсивной цепочки flatMap (на основе ответа Marco13):

static <T extends List> Stream<List<T>> ofCombinations(List<? extends Collection<T>> mapValues, List<T> current) {
    return mapValues.isEmpty() ? Stream.of(current) :
        mapValues.get(0).stream().flatMap(list -> {
            List<T> combination = new ArrayList<T>(current);
            combination.addAll(list);
            return ofCombinations(mapValues.subList(1, mapValues.size()), combination);
        });
}

private static void testStreamCombinations(Map<String, List<List<Integer>>> map) {
    System.out.println("input map: " + map);
    
    ofCombinations(new ArrayList<>(map.values()), Collections.emptyList())
        .forEach(System.out::println);   
}

// invoking test method
testStreamCombinations(map1);
testStreamCombinations(map2);

Тестовый вывод: такой же, как указано выше.

25.10.2020
Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..