Декартово произведение (все комбинации) в массиве многомерных объектов с гибкой длиной - PullRequest
0 голосов
/ 20 апреля 2020

Есть несколько вопросов с ответами на StackOverflow, который показывает, как найти декартово произведение для различных простых массивов. И замечательная статья о RosettaCode . Но я не могу найти решение своей проблемы.

У меня есть массив объектов с элементами, назовем его items:

let items = [{
   id: 1
   quantity: 2
   field: "other_field"
},
{
   id: 2
   quantity: 3
   field: "other_field"
}]

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

let pricing = getPricing(id) //item id

/*
Which will return to us:
*/

pricing = [
    {pricing_id: 1, reagent_items: [/*array of objects, fields exactly items*/]},
    {pricing_id: 2, reagent_items: [/*array of objects, fields exactly items*/]}
]

ПРОБЛЕМА КАРТЕЗИЙСКОГО ПРОДУКТА:

Как вы, возможно, уже поняли, по заголовку ответа я хочу получить все возможные комбинации предметов И reagent_items из цены методы.

Например, если у нас есть два элемента и у каждого элемента (из этих 2) только один метод ценообразования, будет 4 различных комбинации:

  1. 2 элементов по умолчанию с items
  2. первый элемент по умолчанию с items (item[0]) и все все reagent_items с getPricing для item[1]
  3. второй элемент по умолчанию с items (item[1]) и все все reagent_items от getPricing для item[0]
  4. оба reagent_items от getPricing для обоих по умолчанию items

Я буквально не могу sh reagent items до items (или удалить элемент из items) массива, потому что элементы могут То же самое (включая друг друга) Вместо этого Я использую свой собственный Array.prototype.method для добавления / удаления элементов из массива items. Он делает то же самое, что и push / slice, но более элегантно, манипулируя полями id и quantity.

Фактическая проблема заключается в области arrays.length и for ... loop.

Когда мы оцениваем декартово произведение по умолчанию, мы знаем его перед array.length и его элементами. Но в моем случае я должен getPricing каждый элемент, а затем получить массив методов ..

Схема:

Это как:

    Default:        I_1       I_2        ...   N
                   /   \     /   \            / \
Get Pricing:     [I_A, I_B][I_B, I_C]     [IN_J, IN_K],
                                        [IN_Y, IN_X, IN_Z],   

Таким образом, речь идет не о поиске: Cartesian([I_A, I_B],[I_B, I_C]), а о чем-то вроде:

I_1 + I_2
I_1 + (I_B, I_C)
(I_A, I_B) + I_2
(I_A, I_B) + (I_B, I_C)
...

Таким образом, элемент по умолчанию включает друг друга и их reagent_items, и легко найти все комбинации двух элементов, но когда он станет 3 + ..

Мой текущий псевдокод на данный момент:

/* inside async*/
...
let ArrayOfPricing = [] //length 2, where each Array represent Array of `pricing` for each item
Promise.all(items.map(async item => {
   const itemPricing = await getPricing(item.id);
   ArrayOfPricing.push(itemPricing );
})

/**And what's next? **/
for (let item of items) {

}

Так что я не могу понять, что мне делать дальше, на этом этапе.

  • Должен ли я повторять / повторять каждый элемент? Но если это так, даже если я итерирую каждый элемент один за другим, меняю / удаляю его и добавляю его reagent_items (для каждой цены), я все равно не изменяю следующий элемент / элемент в массиве items, а его длина больше затем просто 2, тогда я не получу все комбинации, это будет выглядеть так:
for items
   ↓
  item[1] → for pricing
               → for reagent_items 
                      ↓
               replace item[1] for all reagent_item

  item[2] /** they are still there, but I need iterate over it's pricing , too **/
  item[3]
  • или я мог бы рассчитать все возможные комбинации, посмотрев на длину items и все pricing длина, а затем сформировать и очистить новый массив с фиксированной длиной и pu sh для всех комбинаций. Но если я повторю его для pu sh с for loop ... Я должен объединить элементы, и это будет for loop, inside for loop, inside for .. loop ..

Так что, честно говоря, у меня нет идей. Я не прошу писать полный рабочий код вместо меня, но указываю мне выход из этого l oop. Как получить каждую комбинацию для каждого предмета и «детских предметов» внутри него? Сколько циклов я должен использовать тогда? Я буду благодарен за любую полезную ссылку идея / псевдокод / ​​пост, которая поможет мне разобраться с этим делом. Я также здесь и проверю все комментарии и ответы ниже.

UPD простая версия «от того, что я получаю, к тому, что я хочу»

от это:

[ 
   {
      field: "original, can be cloned for every combination", 
      items: 
         [
            {id: 1, quantity: 2},
            {id: 2, quantity: 3} 
         ]
    }
]

до:

[ 
   {
      field: "original", 
      items: 
         [
            {id: 1, quantity: 2},
            {id: 2, quantity: 3} 
         ]
    },
   {
      field: "combination1", 
      items: 
         [
            {id: 11, quantity: 1}, //from getPricing(item[0])
            {id: 12, quantity: 1}, //from getPricing(item[0])
            {id: 2, quantity: 3} 
         ]
    },
   {
      field: "combination2", 
      items: 
         [
            {id: 1, quantity: 2},
            {id: 22, quantity: 3} //from getPricing(item[1])
            {id: 23, quantity: 3} //from getPricing(item[1])
         ]
    },
   {
      field: "combination3", 
      items: 
         [
            {id: 11, quantity: 1}, //from getPricing(item[0])
            {id: 12, quantity: 1}, //from getPricing(item[0])
            {id: 22, quantity: 3} //from getPricing(item[1])
            {id: 23, quantity: 3} //from getPricing(item[
         ]
    }
    //can be any length according to getPricing of every item, and I modify original array, but we could create a new one.
]

1 Ответ

0 голосов
/ 27 апреля 2020

Как я и обещал, я нашел решение своей проблемы и хочу поделиться им с сообществом StackOverflow.

Псевдокод:

let array = [ 
   {
      field: "original, can be cloned for every combination", 
      items: 
         [
            {id: 1, quantity: 2},
            {id: 2, quantity: 3} 
         ]
    }
]


for (let element of array) {
    let MethodsCombinations = [];
    for await (let forCombinations of element.items.map((item, i) => {
        return getMethod(item.id) //get Method for each item)
    })) {
        MethodsCombinations.push(forCombinations)
    }
    /* Cartesian product */
     let vanilla_CartesianProduct = MethodsCombinations.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []));
    /* Return array of arrays, with objects inside like default array */ 
    /**
    * Other logic with two for loops and merging all the combinations and quantities 
    * with (my own) modified Array.prototype.addItemToArray
    */

}

Я очень благодарен на этот ответ Нины Шольц и ее удивительный профиль StackOverflow со всеми ответами о комбинациях / перестановках и о предоставлении поддержки.

...