首页 > 解决方案 > C# 根据其他元组检查和替换元组值

问题描述

我从编程和 C# 开始,我有两个元组。一个元组表示点列表:

static List<(string, string, string)> PR { get; set; } = new List<(string, string, string)>()
    {
        ("P1", "0", "0"),
        ("P2", "P1", "P1+Height"),
        ("P3", "P1+Width", "P2"),
        ("P4", "P3", "P3+Height")
    };

其中元组列表中的 Item1 代表点名称(P1、P2、P3、P4),Item2 和 Item3 分别代表点的 x 和 y 值的参数公式。

上面列表中第二项中的“P1”应查找以“P1”开头的元组,然后查找该元组中的第二项,在本例中为 0。

我有第二个元组列表,表示计算上述点值所需的参数。

static List<(string, double)> PAR { get; set; } = new List<(string, double)>()
    {
        ("Height", 500),
        ("Width", 1000)
    };

假设我要计算参数公式“P3+Height”的值,如下所示:

P3+高度--> P2(+高度)--> P1+高度(+高度)--> 0(+高度(+高度)--> 0+高度+高度;

最后,我想用实际值(0 + 500 + 500 -> P3+Height = 1000)替换参数字符串,但那是以后关心的问题。

问题:我正在尝试创建一个函数,它可以递归地评估元组列表并保留参数名称,但也会查找相应的元组,直到我们到达结束或退出情况。这就是我现在所处的位置,但我很难在实际工作代码中得到我的思考过程:

        static void Main(string[] args)
    {
        //inputString = "P3+Height"
        string inputString = PR[3].Item3;

        string[] returnedString = GetParameterString(inputString);


        #region READLINE
        Console.ReadLine();
        #endregion
    }

    private static string[] GetParameterString(string inputString)
    {
        string[] stringToEvaluate = SplitInputString(inputString);

        for (int i = 0; i < stringToEvaluate.Length; i++)
        {
            //--EXIT CONDITION
            if (stringToEvaluate[0] == "P1")
            {
                stringToEvaluate[i] = "0";
            }

            else
            {
                if (i % 2 == 0)
                {
                    //Check if parameters[i] is point string
                    var value = PAR.Find(p => p.Item1.Equals(stringToEvaluate[i]));

                    //Check if parameters[i] is double string
                    if (double.TryParse(stringToEvaluate[i], out double result))
                    {
                        stringToEvaluate[i] = result.ToString();
                    }
                    else if (value == default)
                    {
                        //We have a point identifier
                        var relatingPR = PR.Find(val => val.Item1.Equals(stringToEvaluate[i])).Item2;
                        
                        //stringToEvaluate[i] = PR.Find(val => val.Item1.Equals(pointId)).Item2;
                        stringToEvaluate = SearchParameterString(relatingPR);
                    }
                    else
                    {
                        //We have a parameter identifier
                        stringToEvaluate[i] = value.Item2.ToString();
                    }
                }
            }
        }
        return stringToEvaluate;
    }

    private static string[] SplitInputString(string inputString)
    {
        string[] splittedString;
        splittedString = Regex.Split(inputString, Delimiters);
        return splittedString;
    }

谁能指出我如何通过递归或其他更好、更简单的方法来完成这项工作的正确方向?

最后,我需要得到一个像这样的元组列表:

("P1", "0", "0"),
("P2", "0", "500"),
("P3", "1000", "500"),
("P4", "1000", "1000")

提前致谢!

标签: c#recursiontuples

解决方案


我写了一些东西来做这件事——我改变了一些结构来简化代码和运行时,但它仍然返回你期望的元组:

    // first I used dictionaries so we can search for the corresponding value efftiantly: 
    static Dictionary<string, (string width, string height)> PR { get; set; } =
        new Dictionary<string, (string width, string height)>()
    {
            { "P1", ("0", "0") },
            { "P2", ("P1", "P1+Height")},
            { "P3", ("P1+Width", "P2") },
            { "P4", ("P3", "P3+Height") }
    };

    static Dictionary<string, double> PAR { get; set; } = new Dictionary<string, double>()
        {
            { "Height", 500 },
            { "Width", 1000 }
        };

    static void Main(string[] args)
    {
        // we want to "translate" each of the values height and width values
        List<(string, string, string)> res = new List<(string, string, string)>();
        foreach (var curr in PR)
        {
            // To keep the code generic we want the same code to run for height and width- 
            // but for functionality reasons we need to know which it is - so sent it as a parameter.
            res.Add((curr.Key,
                    GetParameterVal(curr.Value.width, false).ToString(),
                    GetParameterVal(curr.Value.height, true).ToString()));
        }

        #region READLINE
        Console.ReadLine();
        #endregion
    }


private static double GetParameterVal(string inputString, bool isHeight)
{
    // for now the only delimiter is + - adapt this and the code when \ as needed
    // this will split string with the delimiter ("+height", "-500", etc..)
    string[] delimiters = new string[] { "\\+", "\\-" };
    string[] stringToEvaluate = 
        Regex.Split(inputString, string.Format("(?=[{0}])", string.Join("", delimiters)));

    // now we want to sum up each "part" of the string
    var sum = stringToEvaluate.Select(x =>
    {
        double result;
        int factor = 1;
        // this will split from the delimiter, we will use it as a factor, 
        // ["+", "height"], ["-", "500"] etc..
        string[] splitFromDelimiter=
            Regex.Split(x, string.Format("(?<=[{0}])", string.Join("|", delimiters)));
        if (splitFromDelimiter.Length > 1) {
            factor = int.Parse(string.Format($"{splitFromDelimiter[0]}1"));
            x = splitFromDelimiter[1];
        }

        if (PR.ContainsKey(x))
        {
            // if we need to continue recursively translate
            result = GetParameterVal(isHeight ? PR[x].height : PR[x].width, isHeight);
        }
        else if (PAR.ContainsKey(x))
        {
            // exit condition
            result = PAR[x];
        }
        else
        {
            // just in case we didnt find something - we should get here
            result = 0;
        }

        return factor * result;
    }).Sum();

    return sum;
}

    }
}

我没有添加任何有效性检查,如果没有找到一个值,它会收到一个 0 的值,但请继续并根据您的需要调整它..


推荐阅读