【问题标题】:How to go from iterative approach to recursive approach如何从迭代方法转向递归方法
【发布时间】:2014-10-13 15:04:50
【问题描述】:

我有一个迭代 C# 循环,它填充了最多 5 列的棋盘格模式。

这些值是成对的,它总是一个标题和每列的多个值,并且它将这些值组合成一个非重复的组合。

从我能想象到的最简单的解决方案开始,看了之后,我认为必须有更好的方法通过递归来解决这个问题。

以下是我迄今为止尝试过的示例:

 List<EtOfferVariant> variants = new List<EtOfferVariant>();

 _containers[0].Variant.ForEach(first =>
 {
     if (_containers.Count > 1)
     {
         _containers[1].Variant.ForEach(second =>
         {
             if (_containers.Count > 2)
             {
                 _containers[2].Variant.ForEach(third =>
                     {
                         EtOfferVariant va = new EtOfferVariant();
                         va.OfferVariant1Type = _containers[0].VariantKey;
                         va.OfferVariant1 = first;
                         va.OfferVariant2Type = _containers[1].VariantKey;
                         va.OfferVariant2 = second;
                         va.OfferVariant3Type = third;
                         va.OfferVariant3 = _containers[3].VariantKey;
                         variants.Add(va);
                     });
             }
             else
             {
                 EtOfferVariant va = new EtOfferVariant();
                 va.OfferVariant1Type = _containers[0].VariantKey;
                 va.OfferVariant1 = first;
                 va.OfferVariant2Type = second;
                 va.OfferVariant2 = _containers[1].VariantKey;
                 variants.Add(va);
             }
         });
     }
     else
     {
         EtOfferVariant va = new EtOfferVariant();
         va.OfferVariant1Type = _containers[0].VariantKey;
         va.OfferVariant1 = first;
         variants.Add(va);
     }
 });

容器由字符串列表(值)和键(标题)组成。

这是一个缩短版OfferVariant 在实际示例中最多计数为 5。

我无法更改初始检查板结构,因为它是由现有数据库提供的。

以下是 2 个容器的数据输入和输出示意图:

容器 1:

  • 钥匙:派
  • 价值观:
    1. 覆盆子
    2. 草莓

容器 2:

  • 关键:喝
  • 值:
    1. 可乐,
    2. 咖啡

生成的输出将由 4 行组成,其中包含

编辑因为它很容易被误解,因为它在这里说明

结果将是由 4 列组成的数据库中的一行

Column 1 | Column 2  | Column 3 | Column 4
Pie      | Raspberry | Drink    | Cola 
Pie      | Raspberry | Drink    | Coffee
Pie      | Strawberry| Drink    | Cola 
Pie      | Strawberry| Drink    | Coffee

EtOfferVariant 是一个包含这些列的 ORM Poco

【问题讨论】:

  • 从您的示例看来,您正在尝试创建笛卡尔积。在这种情况下,您可以编写一个通用算法,其中产品中的集合数不必固定:stackoverflow.com/a/16996888/98607。但是,这不涉及递归。

标签: c# recursion combinatorics iteration


【解决方案1】:

我想您只是想减少重复代码。在这种情况下,只需添加您所知道的数据,并在构建完成后在最后添加变体。唯一的问题是,您需要一个复制构造函数来复制先前运行的值。

List<EtOfferVariant> variants = new List<EtOfferVariant>();

_containers[0].Variant.ForEach(first =>
{
    EtOfferVariant va = new EtOfferVariant();
    va.OfferVariant1Type = _containers[0].VariantKey;
    va.OfferVariant1 = first;
    if (_containers.Count > 1)
    {
        _containers[1].Variant.ForEach(second =>
        {
            va = new EtOfferVariant(va);
            va.OfferVariant2Type = _containers[1].VariantKey;
            va.OfferVariant2 = second;
            if (_containers.Count > 2)
            {
                _containers[2].Variant.ForEach(third =>
                {
                    va = new EtOfferVariant(va);
                    va.OfferVariant3Type = third;
                    va.OfferVariant3 = _containers[3].VariantKey;
                    variants.Add(va);
                });
            } else 
            variants.Add(va);
        });
    } else
    variants.Add(va);
});

...

public EtOfferVariant(EtOfferVariant va){
   this.OfferVariant1Type = va.OfferVariant1Type;
   this.OfferVariant2Type = va.OfferVariant2Type;
   this.OfferVariant3Type = va.OfferVariant3Type;
   this.OfferVariant1 = va.OfferVariant1;
   this.OfferVariant2 = va.OfferVariant2;
   this.OfferVariant3 = va.OfferVariant3;
}

【讨论】:

    【解决方案2】:

    感谢您的回复, Martin Liversage 有点引导我思考, 很难,它不是一个纯笛卡尔积,因为事实上它被分组为后者被展平 和Cines方法给了我正确方向的最后一点我现在通过以下方式解决了这个问题

    在第一步中,我为第一个变体生成初始行

        List<EtOfferVariant> row = new List<EtOfferVariant>();
        _containers.First().Variant.ForEach(o =>
        {
            row.Add(new EtOfferVariant() { OfferVariant1 = o, OfferVariant1Type = _containers.First().VariantKey });
        });
      return BuildVariants(row);
    

    然后运行它

      private List<EtOfferVariant> BuildVariants(List<EtOfferVariant> row, int containerIndex = 1)
        {
            List<EtOfferVariant> final = new List<EtOfferVariant>();
            row.ForEach(y =>
            {
                for (int i = 0; i < _containers[containerIndex].Variant.Count; i++)
                {
                    var ret = MultiplyFromPrevious(y);
                    FillByIndex(ret, _containers[containerIndex].Index, _containers[containerIndex].VariantKey, _containers[containerIndex].Variant[i]);
                    final.Add(ret);
                }
            });
            containerIndex++;
            if (containerIndex < _containers.Count)
               return BuildVariants(final, containerIndex);
            return final;
        }
    

    再次感谢电影

    private EtOfferVariant MultiplyFromPrevious(EtOfferVariant variant)
    {
        EtOfferVariant ret = new EtOfferVariant();
        ret.OfferVariant1 = variant.OfferVariant1;
        ret.OfferVariant2 = variant.OfferVariant2;
        ret.OfferVariant3 = variant.OfferVariant3;
        ret.OfferVariant4 = variant.OfferVariant4;
        ret.OfferVariant5 = variant.OfferVariant5;
    
        ret.OfferVariant1Type = variant.OfferVariant1Type;
        ret.OfferVariant2Type = variant.OfferVariant2Type;
        ret.OfferVariant3Type = variant.OfferVariant3Type;
        ret.OfferVariant4Type = variant.OfferVariant4Type;
        ret.OfferVariant5Type = variant.OfferVariant5Type;
    
        return ret;
    }
    

    我还将列拆分为一个自己的方法,但它所做的就是获取索引并将值映射到对象,没什么特别的

    再次感谢大家,这真的放松了代码

    【讨论】:

      【解决方案3】:

      如果您首先转换容器中的字典,您似乎可以通过笛卡尔积得到想要的结果。

      var containers = new List<Dictionary<string, IEnumerable<string>>>
                          {
                              new Dictionary<string, IEnumerable<string>>() {{"Pie", new [] {"Raspberry", "Strawbery"}}},
                              new Dictionary<string, IEnumerable<string>>() {{"Drink", new [] {"Cola", "Coffee"}}},
                              new Dictionary<string, IEnumerable<string>>() {{"Bread", new [] {"Bagel", "Pretzel", "Scone"}}},
                          };
      
      var flatten = containers.Select(dict => dict.SelectMany(c => c.Value.Select(v => new {type = c.Key, name = v})));
      
      foreach (var combo in CartesianProduct(flatten))
      {
          Console.WriteLine(string.Join(", ", combo.Select(c => c.type + ": " + c.name)));
      }
      

      来自https://stackoverflow.com/a/3098381/44620的笛卡尔积法

      public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(IEnumerable<IEnumerable<T>> sequences)
      {
          IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
          return sequences.Aggregate(
              emptyProduct,
              (accumulator, sequence) => 
                  from accseq in accumulator 
                  from item in sequence 
                  select accseq.Concat(new[] {item})                         
              );
      }
      

      输出:

      Pie: Raspberry, Drink: Cola, Bread: Bagel
      Pie: Raspberry, Drink: Cola, Bread: Pretzel
      Pie: Raspberry, Drink: Cola, Bread: Scone
      Pie: Raspberry, Drink: Coffee, Bread: Bagel
      Pie: Raspberry, Drink: Coffee, Bread: Pretzel
      Pie: Raspberry, Drink: Coffee, Bread: Scone
      Pie: Strawbery, Drink: Cola, Bread: Bagel
      Pie: Strawbery, Drink: Cola, Bread: Pretzel
      Pie: Strawbery, Drink: Cola, Bread: Scone
      Pie: Strawbery, Drink: Coffee, Bread: Bagel
      Pie: Strawbery, Drink: Coffee, Bread: Pretzel
      Pie: Strawbery, Drink: Coffee, Bread: Scone
      

      【讨论】:

      • 谢谢,我之前尝试过这种方法,但是我很难将聚合值放入正确的列中,因为我的输出似乎不清楚,所以我已经编辑了这个问题
      猜你喜欢
      • 1970-01-01
      • 2021-08-09
      • 1970-01-01
      • 1970-01-01
      • 2016-11-10
      相关资源
      最近更新 更多