简体   繁体   English

具有灵活长度的多维对象数组中的笛卡尔积(所有组合)

[英]Cartesian product (all combinations) in array of multi-dimentonal objects with flexible length

There are several questions with answers on StackOverflow which shows how to find Cartesian product for various simple arrays. StackOverflow 上有几个问题的答案,显示了如何为各种简单的 arrays 找到笛卡尔积。 And a wonderful article on RosettaCode .还有一篇关于RosettaCode的精彩文章。 But I can't find any solution for my problem.但我找不到任何解决我的问题的方法。

I have an array of object with items, let's call it items :我有一个带有项目的 object 数组,我们称之为items

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

Every item in this array have a pricing/crafting method and we could receive it by request.这个数组中的每个项目都有一个定价/制作方法,我们可以通过请求接收它。

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*/]}
]

CARTESIAN PRODUCT PROBLEM:笛卡尔积问题:

As you may already understand, according to the answer's title, I want to receive all possible combinations of items AND reagent_items from pricing methods.正如您可能已经理解的那样,根据答案的标题,我想从定价方法中接收所有可能的 itemsreagent_items 组合。

For example, if we have two items and all every item (of this 2) have just one pricing method, there will be 4 different combinations:例如,如果我们有两个项目,并且所有每个项目(这 2 个)都只有一种定价方法,那么将有 4 种不同的组合:

  1. 2 default items from items来自items
  2. first default item from items ( item[0] ) and all all reagent_items from getPricing for item[1] items ( item[0] ) 中的第一个默认项目和item[1]getPricing中的所有所有试剂项目
  3. second default item from items ( item[1] ) and all all reagent_items from getPricing for item[0] items ( item[1] ) 中的第二个默认项目以及item[0]getPricing中的所有所有 reagent_items
  4. both reagent_items from getPricing for both default items来自getPricing的两个默认项目的两个试剂items

I literally can't push reagent items to items (or remove item from items ) array, because items can be the same (include each other) Instead of it, I am using my own Array.prototype.method for adding/removal items from items array.我实际上不能将reagent items推送到items (或从项目中删除items )数组,因为项目可以是相同的(包括彼此)而不是它, 我使用我自己的Array.prototype.method来添加/删除项目items数组。 It does just the same as push / slice but in more elegant way, manipulating with id and quantity fields.它的作用与push / slice相同,但以更优雅的方式使用idquantity字段进行操作。

The actual problem lies in the field of arrays.length and for... loop .实际问题出在 arrays.length 和for... loop领域。

When we evaluate default Cartesian product we know before the array.length and it's elements.当我们评估默认笛卡尔积时,我们知道 array.length 和它的元素。 But in my case I should getPricing every items, then receive array of methods..但在我的情况下,我应该getPricing每个项目定价,然后接收方法数组..

Schema:架构:

It's like:就像是:

    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],   

So it's not about finding: Cartesian([I_A, I_B],[I_B, I_C]) but something like:所以这不是要找到: 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)
...

So default item includes each others and their reagent_items and it's simple to find all combinations of two items, but when it's become 3+..所以默认项目包括彼此和他们的reagent_items项目,很容易找到两个项目的所有组合,但是当它变成 3+..

My current pseudo code for now:我目前的伪代码:

/* 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) {

}

So I can't understand what should I do next, at this stage.所以我不明白在这个阶段我下一步该怎么做。

  • Should I loop/iterate every item?我应该循环/迭代每个项目吗? But if so, even if I iterate every item one-by-one and change/remove it and add it's reagent_items (for every pricing) I still don't change the next item/element in array of items and it's length more then just 2, then I won't receive all the combinations, it will be like:但如果是这样,即使我逐个迭代每个项目并更改/删除它并添加它的 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]
  • or I could calculate all possible combinations by looking for items length and all pricing length and then form and empty new array with fixed length and push to all the combinations.或者我可以通过查找items长度和所有pricing长度来计算所有可能的组合,然后形成并清空具有固定长度的新数组并推送到所有组合。 But if I iterate over it for push with for loop ... I should combine items and it will be for loop, inside for loop, inside for.. loop ..但是,如果我用for loop遍历它以进行推送......我应该组合项目,它将是for loop, inside for loop, inside for.. loop ..

So to be honest I am out of ideas.所以说实话,我没有想法。 I don't ask to write full working code instead of me, but to point me the way out of this loop.我不要求代替我编写完整的工作代码,而是为我指出摆脱这个循环的出路。 How to get every combination for every item and "baby-items" inside of it?如何获得其中每个项目和“婴儿项目”的每个组合? How many cycles should I use then?那我应该使用多少个周期? I'll be grateful for any useful idea/pseudocode/post link which will help me to deal with this case.我将不胜感激任何有用的想法/伪代码/帖子链接,这将帮助我处理这种情况。 I'm also here and will check all the comments and answers below.我也在这里,将检查下面的所有评论和答案。

UPD a simple version of «from what I get, to what I want» UPD 一个简单版本的«从我得到的,到我想要的»

from this:由此:

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

to:至:

[ 
   {
      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.
]

As I promised, I have found a solution of my problem and I'd like to share it with StackOverflow Community.正如我所承诺的,我找到了解决问题的方法,我想与 StackOverflow 社区分享。

Pseudo-code:伪代码:

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
    */

}

I am very grateful to this Nina Scholz's answer and her awesome StackOverflow profile with all answers about combinations/permutations and for providing a support.我非常感谢Nina Scholz 的回答她出色的 StackOverflow个人资料,其中包含有关组合/排列的所有答案以及提供支持。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM