Поиск всех возможных комбинаций значений между двумя массивами - PullRequest
5 голосов
/ 19 мая 2011

У меня есть два массива строк, не обязательно одинаковой длины, я хочу найти все возможные «наборы» комбинаций между двумя значениями из массивов, без повторов из любого массива.
Например, с учетом массивов:
{"А1", "А2", "А3"}
{"B1", "B2"}
В результате я хочу следующие наборы:
{("A1", "B1"), ("A2", "B2")}
{("A1", "B1"), ("A3", "B2")}
{("A1", "B2"), ("A2", "B1")}
{("A1", "B2"), ("A3", "B1")}
{("A2", "B1"), ("A3", "B2")}
{("A2", "B2"), ("A3", "B1")}

Мое общее руководство - создать рекурсивную функцию, которая принимает в качестве параметра два массива и удаляет каждую «выбранную» строку за раз, вызывая себя до тех пор, пока один из массивов не станет пустым, однако я немного обеспокоен проблемами с производительностью (мне нужно чтобы запустить этот код на 1000 пар строковых массивов).
Кто-нибудь может направить меня к эффективному способу сделать это?

Ответы [ 7 ]

9 голосов
/ 19 мая 2011

Может быть полезно думать о двух массивах как о сторонах стола:

        A1      A2      A3
---+-------+-------+-------+
B1 | B1,A1 | B1,A2 | B1,A3 |
---+-------+-------+-------+
B2 | B2,A1 | B2,A2 | B2,A3 |
---+-------+-------+-------+

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

{B1,A1} {B1,A2} {B1,A3} {B2,A1} {B2,A2} {B2,A3}

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

      B1,A1 B1,A2 B1,A3 B2,A1 B2,A2 B2,A3
-----+-----+-----+-----+-----+-----+-----+
B1,A1|     |  X  |  X  |  X  |  X  |  X  |
-----+-----+-----+-----+-----+-----+-----+
B1,A2|     |     |  X  |  X  |  X  |  X  |
-----+-----+-----+-----+-----+-----+-----+
B1,A3|     |     |     |  X  |  X  |  X  |
-----+-----+-----+-----+-----+-----+-----+
B2,A1|     |     |     |     |  X  |  X  |
-----+-----+-----+-----+-----+-----+-----+
B2,A2|     |     |     |     |     |  X  |
-----+-----+-----+-----+-----+-----+-----+
B2,A3|     |     |     |     |     |     |
-----+-----+-----+-----+-----+-----+-----+

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

2 голосов
/ 06 апреля 2015

Ваша задача эквивалентна следующей проблеме:

Постановка задачи:
Даны два вектора A с размером n, B с размером m, где n <= m.
A = [0, 1, 2, ..., n - 1].
B = [0, 1, 2, ..., m - 1].
Найти все возможные инъективные и несюръективные отображения от A до B.One possible injective and non-surjective mapping

Решение :
Поскольку размер A меньше, в одном отображении число соответствий равно размеру A, то есть n.

Затем мы генерируем все возможные перестановки B, так что начинающиеся n элементов в каждой перестановке могут иметь взаимно однозначное соответствие с элементами в A.

Первые несколько перестановок и отображенийсделать следующее: Permutation 1 Permutation 2 Permutation 3 Permutation 4

Реализация:

class Helper {
public:
    /**
     * @brief generateArray
     * @param size
     * @return A vector [0, 1, ..., size - 1]
     */
    vector<int> generateArray(int size) {
        vector<int> arr;
        for (int i = 0; i < size; ++i) {
            arr.push_back(i);
        }
        return arr;
    }

    /**
     * @brief generateMatches
     * @param n, cardinality of the vector X, where X = [0,1, ..., n - 1].
     * @param m, cardinality of the vector Y, where Y = [0,1, ..., m - 1].
     * @return All possible injective and non-surjective mappings 
     * from the smaller vector to the larger vector.
     */
    vector<vector<pair<int, int> > > generateMatches(int n, int m) {
        // Deal with n > m. Swap back when generating pairs.
        bool swapped = false;
        if (n > m) {
            swapped = true;
            swap(n, m);
        }
        // Now n is smaller or equal to m
        vector<int> A = generateArray(n);
        vector<int> B = generateArray(m);
        vector<vector<pair<int, int> > > matches;
        // Generate all the permutations of m
        do {
            vector<pair<int, int> > match;
            for (int i = 0; i < n; ++i) {
                pair<int, int> p;
                if (swapped) {
                    // Swap back to the original order.
                    p = make_pair(A[i], B[i]);
                } else {
                    p = make_pair(B[i], A[i]);
                }
                match.push_back(p);
            }
            matches.push_back(match);
                // Generate next permutation.
        } while(next_permutaion(B.begin(), B.end())); 
        return matches;
    }
};
2 голосов
/ 19 мая 2011

очень простой способ

string[] arr = new string[3];
        string[] arr1 = new string[4];
        string[] jointarr = new string[100];

        for (int i = 0; i < arr.Length; i++)
        {
            arr[i] = "A" + (i + 1);
        }

        for (int i = 0; i < arr1.Length; i++)
        {
            arr1[i] = "B" + (i + 1);
        }

        int k=0;
        for (int i = 0; i < arr.Length; i++)
        {
            for (int j = 0; j < arr1.Length; j++)
            {
                jointarr[k] = arr[i] + " " + arr1[j];
                k++;
            }
        }
0 голосов
/ 23 мая 2016

Я посмотрел на этот вызов, когда увидел головоломку в стиле кроссворда, где у каждого квадрата есть номер, и вам нужно найти, какая буква соответствует какому числу, чтобы слова были правильными.Зная, что я касаюсь уже даных ответов, я постараюсь обобщить проблему и покажу, как ее можно рекурсивно решить.

В случае слова x меньший массив A представляет собой последовательность чисел,и большой массив B содержит буквы алфавита.Задача состоит в том, чтобы присвоить каждому номеру букву и найти все возможные комбинации.Обычно мы имеем:

A={1,2,...m} and B={1,2,....n}     n>=m

Каждый возможный результат может быть записан в виде массива C с m элементами, где элемент i содержит значение j для пары A (i) B (j).Общее количество перестановок, то есть C-массивов, равно n (n-1) ..... (n-m + 1) или более аккуратно: n! / (M + 1)!

Это число следует из мысли, что когда первый элемент A связан с любым из элементов в B, второй элемент A может быть связан с любым элементом , за исключением , который был взят первым,и т. д. и т.1018 * Этот код не будет работать для произвольной длины A, и было бы неудобно писать для больших m, поэтому лучше сделать это рекурсивным с помощью процедуры AllPairs, которая может вызывать себя:

   AllPairs (A,B,C)
    if Size(A)>1             ' check no of elements in A        
      for i=1 to Size(B)
       C(Size(C)-Size(A)+1)= B(i)
       A'=Remove element 1 from A
       B'=Remove element i from B
       Call AllPairs(A',B',C)     'recursive call
      Next i
    else                          ' only one element in A
      for j=1 to Size(B)
      C(Size(C)) = B(i)  'looping last element in C through all unused in B
      Collect.ADD(C)      'collect C-arrays here for later use
      Next j                 
  End AllPairs

Обратите внимание, чтоC изначально представляет собой пустой массив с таким же размером, что и A (может также быть копией A).C остается того же размера, в то время как A и B последовательно уменьшаются, пока A не содержит только один элемент, и рекурсивный вызов заканчивается.Это сделало бы это.Возможно (со всем уважением) это похоже на ответ кода Джинги Чжэна - (я не могу сказать).Мое намерение здесь состоит в том, чтобы попытаться дать легкую интуитивную версию псевдокода.Это решение может быть найдено в VB здесь.

0 голосов
/ 05 июня 2011

Если я правильно понимаю вашу проблему, все комбинации могут быть получены с помощью:

  • выбрал 2 разных элемента {A_i, A_j} из A,
  • выбрал 2 разных элемента {B_k, B_l} изB,
  • составляет 2 комбинации с этими элементами { (A_i, B_k), (A_j, B_l) }, { (A_i, B_l), (A_j, B_k) }.

Со всеми комбинациями из 2 подмножеств элементов из A и B вы получаете все комбинации, которые вы ищете.

Существует |A| * (|A| - 1) * |B| * (|B| - 1) / 2 комбинаций.

Легкая реализация с 4 циклами:

for i = 1 ... |A|
  for j = i+1 ... |A|
    for k = 1 ... |B|
      for l = k+1 ... |B|
        make 2 combinations {(A_i, B_k),(A_j, B_l)}, {(A_i, B_l), (A_j, B_k)}
0 голосов
/ 19 мая 2011

Есть много вопросов (и ответов) относительно комбинаций двух списков на этом сайте (см. Боковую панель).Ваш вариант использования выглядит поверхностно иначе, если я правильно его понимаю.

Разве не достаточно иметь метод

IEnumerable<Tuple<string, string>> Combinations(
  IEnumerable<string> list1, 
  IEnumerable<string> list2) {}

(который существует в различных формах и размерах уже в «дубликатах»?'), а затем используйте его, выполнив следующие действия (домашняя работа = вы заполняете детали):

Перебирайте все комбинации списков 1 и 2 (используя что-то подобное выше) и

  • Фильтр списка 1 по первому элементу текущей комбинации
  • Фильтр списка 2 по второму элементу текущей комбинации
  • Объединить текущую комбинацию со всеми возможными комбинациями отфильтрованных списков (используя что-то похожее на метод выше)
0 голосов
/ 19 мая 2011

Это не совсем та же проблема, но есть решение, которое я сделал для следующего вопроса, который, вероятно, будет хорошей отправной точкой:

Массив комбинаций массивов

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...