【问题标题】:Converting nested for loops with a depth of n转换深度为 n 的嵌套 for 循环
【发布时间】:2014-08-28 06:41:04
【问题描述】:

我一直在尝试构建一个递归函数来替换下面的n个深度嵌套循环算法,深度会根据2到n(很可能小于20)的任意组合长度而变化

    Edit: removed confusing code

我已经搜索了这个网站,发现了 Converting nested loopMore nested loop conversions,但我无法调整它们以输出我需要的东西。

或者我可能只是看错了,根本不需要递归函数。

尝试在 C# 中执行此操作,感谢您的帮助。

编辑:希望这能解释更多。

我想做的是找到选项和金额的最佳组合,以便在不超出预算的情况下给我最大的回报。

所以我有一个满足我要求的选项的精简列表,然后我想将它们输入到这个程序/脚本中以获得具有高回报的最佳组合,我还需要通过购买多个选项来降低风险通常是 3-10

所以下面是我目前固定深度为 3 的完整代码:

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    namespace Combinations
    {
        class Program
        {
            static void Main(string[] args)
            {

                Stopwatch stopwatch = new Stopwatch();

                List<option> options = new List<option> {
                            new option("A", 6.50, 0.18, 25000, 3),
                            new option("B", 23.00, 0.59, 25000, 3),
                            new option("C", 27.50, 0.60, 25000, 3),
                            new option("D", 21.00, 0.40, 25000, 3),
                            new option("E", 16.00, 0.30, 25000, 3),
                            new option("F", 7.00, 0.13, 25000, 3),
                            new option("G", 22.50, 0.38, 25000, 3),
                            new option("H", 27.00, 0.45, 25000, 3),
                            new option("I", 13.00, 0.20, 25000, 3),
                            new option("J", 20.50, 0.30, 25000, 3),
                            new option("K", 17.50, 0.25, 25000, 3),
                            new option("L", 10.50, 0.15, 25000, 3),
                            new option("M", 29.00, 0.41, 25000, 3),
                            new option("N", 26.50, 0.37, 25000, 3),
                            new option("P", 15.50, 0.21, 25000, 3),
                            new option("Q", 16.00, 0.20, 25000, 3),
                            new option("R", 10.00, 0.12, 25000, 3),
                            new option("S", 25.00, 0.30, 25000, 3),
                            new option("T", 27.00, 0.32, 25000, 3),
                            new option("U", 22.00, 0.25, 25000, 3),
                            new option("V", 26.50, 0.30, 25000, 3),
                            new option("W", 27.00, 0.30, 25000, 3),
                            new option("X", 14.50, 0.16, 25000, 3),
                            new option("Y", 28.50, 0.31, 25000, 3),
                            new option("Z", 28.50, 0.30, 25000, 3)
                        };
                stopwatch.Start();
                IEnumerable<List<option>> combinations = GetCombination(options, 3);
                stopwatch.Stop();
                Console.WriteLine("Combinations - Time elapsed: {0}", stopwatch.Elapsed);

                stopwatch.Start();
                bestFit(combinations);
                stopwatch.Stop();
                Console.WriteLine("Best Fit - Time elapsed: {0}", stopwatch.Elapsed);

                Console.ReadKey();
            }

            static IEnumerable<List<option>> GetCombination(List<option> list, int _size)
            {
                double count = Math.Pow(2, list.Count);
                List<option> combination = new List<option>();

                int size = 0;

                for (int i = 1; i <= count - 1; i++)
                {
                    for (int j = 0; j < list.Count; j++)
                    {
                        if (((i >> j) & 1) == 1)
                        {
                            combination.Add(list[j]);
                            size++;
                        }
                    }

                    if (size == _size)
                    {
                        yield return combination;
                    }
                    combination.Clear();
                    size = 0;
                }
            }

            static void bestFit(IEnumerable<List<option>> combinations)
            {
                double max = 0d;
                double results = 0d;
                double total = 0d;
                string output = "";
                string tmpOutput = "";

                int y0 = 0;
                int y1 = 1;
                int yn = 2;

                foreach (var combination in combinations)
                {
                    option A1 = combination[y0];
                    for (int x1 = A1.lower; x1 < A1.upper; x1++)
                    {
                        option A2 = combination[y1];
                        for (int x2 = A2.lower; x2 < A2.upper; x2++)
                        {
                            option An = combination[yn];
                            for (int xn = An.lower; xn < An.upper; xn++)
                            {
                                int[] counts = { x1, x2, xn };
                                int i = 0;
                                foreach (option objOption in combination)
                                {
                                    results += objOption.bid * 100 * counts[i] / objOption.cash;
                                    total += (objOption.strike - objOption.bid) * 100 * counts[i];
                                    tmpOutput += objOption.symbol + " STO " + counts[i].ToString() + " @ $" + objOption.strike + ", ";

                                    i++;
                                }

                                if (results > max && total < A1.cash)
                                {
                                    output = tmpOutput.Remove(tmpOutput.Length - 2) + " for a gain of " + results*100 + "% using a total of $" + total;
                                    max = results;
                                }
                                results = 0d;
                                total = 0d;
                                tmpOutput = "";
                            }
                        }
                    }

                }
                Console.WriteLine(output);
            }
        }

        class option
        {
            public string symbol { get; set; }
            public double strike { get; set; }
            public double bid { get; set; }
            public double cash { get; set; }
            public int lower;
            public int upper;

            public option(string _symbol, double _strike, double _bid, double _cash, int _trades)
            {
                this.symbol = _symbol;
                this.strike = _strike;
                this.bid = _bid;
                this.cash = _cash;

                double tradeCash = _cash / _trades;

                this.lower = (int)((0.25 * tradeCash) / ((_strike - _bid) * 100));
                this.upper = (int)((1.25 * tradeCash) / ((_strike - _bid) * 100));

            }
        }
    }

这应该给出以下输出:

Combinations - Time elapsed: 00:00:00.0002575
A STO 15 @ $6.5, B STO 3 @ $23, D STO 4 @ $21 for a gain of 2.428% using a total of $24443
Best Fit - Time elapsed: 00:00:11.9196411

希望这有助于解决问题。

【问题讨论】:

  • 你想用这个做什么?
  • 很奇怪你预先计算所有这些计数,然后在内部循环中一个一个地使用它们......我不认为你真的需要那些完全没有
  • 啊哈,这个名字,看得我眼花:)你想做什么?

标签: c# recursion


【解决方案1】:

似乎您只使用for 循环来生成您的count 条目。我首先将这部分重构为如下内容:

public struct Bound
{
    public int Lower { get; set; }
    public int Upper { get; set; }
}

public static class Counting
{
    public static IEnumerable<int[]> Indizes(this Bound[] bounds)
    {
        return Indizes(bounds, 0);
    }

    static IEnumerable<int[]> Indizes(this Bound[] bounds, int index)
    {
        if (index >= bounds.Length)
            yield return new int[] {};
        else
        {
            foreach(var comb in Indizes(bounds, index+1))
            {
                for (var i = bounds[index].Lower; i < bounds[index].Upper; i++)
                {
                    var newArr = new int[comb.Length + 1];
                    Array.Copy(comb, 0, newArr, 1, comb.Length);
                    newArr[0] = i;
                    yield return newArr;
                }
            }
        }
    }
}

remark很可能你可以更快地得到这个,但我认为它向你展示了如何使用递归来做这样的思考

有了这样的东西(用你的数据结构替换 Bound 结构 - 它只是在那里,所以我可以测试我的代码)你的 insane-循环简化为:

   foreach(var combination in combinations)
   {
        foreach (var counts in Counting.Indizes(combination))
        {
            int i = 0;
            foreach (myClass objMyClass in combination)
            {
               results += objMyClass.a * 100 * counts[i] / objMyClass.b;
               total += (objMyClass.c - objMyClass.a) * 100 * counts[i];
               tmpOutput += objMyClass.symbol + " count " + counts[i].ToString() + ", ";
               i++;
            }
            // ...
        }
   }

对于其余部分,我对您的代码不够了解,无法提供任何建议

【讨论】:

  • 谢谢,我会先提供您的代码,看看是否能满足我的需要。我已经用我完整的工作开发代码更新了我的帖子,给了我一个输出。如果您想了解一下。
猜你喜欢
  • 1970-01-01
  • 2012-12-01
  • 2017-08-08
  • 2012-11-06
  • 2020-11-26
  • 1970-01-01
  • 2020-05-25
  • 1970-01-01
  • 2021-09-16
相关资源
最近更新 更多