【问题标题】:Recursive function for every number combination每个数字组合的递归函数
【发布时间】:2016-03-03 01:56:47
【问题描述】:

为了提供一些背景信息:我正在开发一个算法问题构建器,最终用户可以在其中输入变量,为其分配范围和规则,在公式中使用它们并获得 (x) 个问题。

我目前需要使用变量名称 [a]、[b]、[c].. 等的键填充 x 数量的 x 个元素的字典,每个值都是唯一的,并且每个它们可能达到的范围的可能性;即 a = 1 - 100,b = 1 - 50 等等。

So 1st dict would be:
[a] = 1
[b] = 1
[c] = 1

2nd dict
[a] = 2
[b] = 1
[c] = 1

是否有一个简单的递归函数可以比迭代函数更好地处理这个问题?

感谢您的帮助!

【问题讨论】:

  • 为什么迭代解决方案不够?
  • 你想要的是范围的笛卡尔积。这个网站上有很多关于这个的问题;尝试stackoverflow.com/questions/4073713/… 开始。
  • @GerardSexton 没有特别的理由说明它不够,我只是发现递归算法更高效、更优雅。
  • 感谢@EricLippert 的提示,我会调查的!
  • @GerardSexton - 在我看来,变量名称的数量不是固定的,因此递归方法比迭代更容易编写。弹出头部并递归尾部。

标签: c# recursion formula equation


【解决方案1】:

如果我从一个可以代表你的值范围的结构开始,像这样:

public struct Range
{
    public int Minimum { get; set; }
    public int Maximum { get; set; }
}

...那么我可以像这样表示您的输入:

var inputs = new Dictionary<string, Range>()
{
    { "a", new Range() { Minimum = 1, Maximum = 3 } },
    { "b", new Range() { Minimum = 1, Maximum = 2 } },
    { "c", new Range() { Minimum = 1, Maximum = 2 } },
};

...然后我可以像这样构建结果:

Func<IEnumerable<KeyValuePair<string, Range>>, IEnumerable<Dictionary<string, int>>> build = null;
build =
    kvps =>
    {
        if (kvps.Skip(1).Any())
        {
            return
                from kvp in kvps.Take(1)
                from n in Enumerable.Range(kvp.Value.Minimum, kvp.Value.Maximum - kvp.Value.Minimum + 1)
                from r in build(kvps.Skip(1))
                select new[] { new KeyValuePair<string, int>(kvp.Key, n) }.Concat(r).ToDictionary(x => x.Key, x => x.Value);
        }
        else
        {
            return
                from kvp in kvps
                from n in Enumerable.Range(kvp.Value.Minimum, kvp.Value.Maximum - kvp.Value.Minimum + 1)
                select new[] { new KeyValuePair<string, int>(kvp.Key, n) }.ToDictionary(x => x.Key, x => x.Value);
        }
    };

这会产生以下字典列表:

a=1, b=1, c=1 a=1, b=1, c=2 a=1, b=2, c=1 a=1, b=2, c=2 a=2, b=1, c=1 a=2, b=1, c=2 a=2, b=2, c=1 a=2, b=2, c=2 a=3, b=1, c=1 a=3, b=1, c=2 a=3, b=2, c=1 a=3, b=2, c=2

下面是对主要查询的解释:

from kvp in kvps.Take(1)

kvps可枚举中获取第一个元素(这是可枚举的“头部”)

from n in Enumerable.Range(kvp.Value.Minimum, kvp.Value.Maximum - kvp.Value.Minimum + 1)

MinimumMaximum 生成n 的所有值。

from r in build(kvps.Skip(1))

在列表的“尾部”递归调用build,生成所有可能的尾部字典

select new[] { new KeyValuePair<string, int>(kvp.Key, n) }.Concat(r).ToDictionary(x => x.Key, x => x.Value);

使用Key 和值n 创建一个新的KeyValuePair&lt;string, int&gt;[],并在创建新字典时连接尾部(r) 中的每个值。

【讨论】:

  • 非常感谢@Enigmativity!有没有可能你可以在迭代块中添加一些 cmets 来解释发生了什么?再次干杯!
  • @daniel-schofield93 - 完成。
猜你喜欢
  • 2019-04-09
  • 1970-01-01
  • 2017-09-16
  • 2013-01-06
  • 1970-01-01
相关资源
最近更新 更多