lds
发布于 2025-03-23 / 13 阅读
0

函数迭代的用处

仅以C#示例,其他开发语言大同小异。(环境.net8)

除非需要,否则不建议使用迭代函数,写不好容易死循环。

1.计算进度

//有时候在耗时操作中需要同一代码执行多次,每次循环还与上次调用有关,一般JavaScript中用的多
//在某些时候,for或while循环无法确定什么时候该结束时使用这种方法比较好

public class Data
{
    public required string Name { get; set; }
    public required string Value { get; set; }
}
private static readonly List<Data> datas =
[
    new () { Name="测试1",Value = "A" },
    new () { Name="测试2",Value = "B" },
    new () { Name="测试3",Value = "C" },
    new () { Name="测试4",Value = "D" },
    new () { Name="测试5",Value = "E" },
    new () { Name="测试6",Value = "F" },
    new () { Name="测试7",Value = "G" },
    new () { Name="测试8",Value = "H" },
];
private int curr = 0;
public async Task Iteration(int i,Action<bool> callback)
{
    var data = datas[curr];
    Console.WriteLine($"进度{curr}=> Name:{data.Name} Value:{data.Value}");
    //耗时操作
    await Task.Delay(1000);
    //if (err){
    //    callback.Invoke(false); //出错时执行
    //} else {
    curr++;
    if (curr < datas.Count)
    {
        await Iteration(curr,callback);
    }
    else callback?.Invoke(true);
    //}
}

public void Run()
{
    var waitting = new ManualResetEvent(false);
    var _ = Iteration(0, (data) =>
    {
        Console.WriteLine($"结果:{data}");
        waitting.Set();
    });
    //相当于主线程继续运行
    waitting.WaitOne();
    Console.WriteLine("执行完成");
    waitting.Close();
    waitting.Dispose();
}
//Run() 结果:
/**
标准输出: 
进度0=> Name:测试1 Value:A
进度1=> Name:测试2 Value:B
进度2=> Name:测试3 Value:C
进度3=> Name:测试4 Value:D
进度4=> Name:测试5 Value:E
进度5=> Name:测试6 Value:F
进度6=> Name:测试7 Value:G
进度7=> Name:测试8 Value:H
结果:True
执行完成
*/

2.树形结构联动处理

//重复次数扩展函数
public static string Repeat(this string target, int count)
{
    var sb = new StringBuilder();
    for (var i = 0; i < count; i++)
    {
        sb.Append(target);
    }
    var res = sb.ToString();
    sb.Clear();
    return res;
}
////////////////主要代码
public class Node
{
    public required int level { get; set; }
    //public bool target { get; set; } = false;
    //如果是菜单类的话 菜单展开状态
    public bool expand { get; set; } = false;
    public required string name { get; set; }
    public List<Node>? children { get; set; }
    //迭代查询
    public Node? Query(string nodeName)
    {
        if (name == nodeName)
        {
            //赋值状态
            //target = true;
            expand = true;
            return this;
        }
        if (children == null) return null;
        foreach (var node in children)
        {
            var nd = node.Query(nodeName);
            if (nd == null) continue;
            /// 示例1 返回最上层(非root,需要返回root的话return this)
            else
            {
                expand = true;
                return node;
            }
            /// 示例2 返回目标层
            //else return nd;
            /// 示例3 查询上一级
            //else if (nd.target)
            //{
            //    //状态置回 不置回的话root关联层级会因为多次查询而出错
            //    nd.target = false;
            //    expand = true;
            //    return this;
            //}
            //else
            //{
            //    expand = true;
            //    return nd;
            //}
        }
        return null;
    }
    //也是个迭代函数
    public void Unexpand() //全折叠(懒省事)
    {
        expand = false;
        children?.ForEach(a=>a.Unexpand());
    }
    public override string ToString()
    {
        return $"\r\n{"\t".Repeat(level)}name:{name};expand:{expand};children:{(children == null ? "null" : $"[{children?.Select(a => a.ToString()).Aggregate((a, b) => $"{a},{b}")}\r\n{"\t".Repeat(level)}]")}";
    }
}

private static Node root = new()
{
    level = 0,
    name = "0",
    children = [
    new () { level = 1, name="1",
        children = [
            new() { level = 2, name="1A" },
            new() { level = 2,  name = "1B" },
            new() { level = 2,  name="1C",
                children = [
                    new() { level = 3, name="1C1"},
                    new() { level = 3, name="1C2" },
                    new() { level = 3, name = "1C3" }
                ]}
        ] },
    new () { level = 1, name="2",
        children = [
            new() { level = 2, name="2A" },
            new() { level = 2, name = "2B",
                children = [
                    new() { level = 3, name = "2B1" },
                    new() { level = 3, name = "2B2" },
                    new() { level = 3, name = "2B3" }
                ] },
            new() { level = 2, name = "2C" }
        ] },
    new () { level = 1, name="3",
        children = [
            new() { level = 2, name = "3A",
                children = [
                    new() { level = 3, name = "3A1" },
                    new() { level = 3, name = "3A2" },
                    new() { level = 3, name = "3A3" }
                ] },
            new() { level = 2, name = "3A1" },
            new() { level = 2, name = "3A2" }
        ] },
    ]
};

private void ForQuery(string query)
{
    Console.WriteLine($"查找{query}...");
    var node = root.Query(query);
    Console.WriteLine($"查询结果\t{(node == null ? "null" : node.ToString())}\r\n");
    root.Unexpand();//展开状态置回
}

public void Run()
{
    ForQuery("3A");
    ForQuery("1B");
    ForQuery("4C");
    ForQuery("3A2");
}
/// 结果
/**
标准输出: 
  查找3A...
  查询结果	
  	name:3;expand:True;children:[
  		name:3A;expand:True;children:[
  			name:3A1;expand:False;children:null,
  			name:3A2;expand:False;children:null,
  			name:3A3;expand:False;children:null
  		],
  		name:3A1;expand:False;children:null,
  		name:3A2;expand:False;children:null
  	]
  
  查找1B...
  查询结果	
  	name:1;expand:True;children:[
  		name:1A;expand:False;children:null,
  		name:1B;expand:True;children:null,
  		name:1C;expand:False;children:[
  			name:1C1;expand:False;children:null,
  			name:1C2;expand:False;children:null,
  			name:1C3;expand:False;children:null
  		]
  	]
  
  查找4C...
  查询结果	null
  
  查找3A2...
  查询结果	
  	name:3;expand:True;children:[
  		name:3A;expand:True;children:[
  			name:3A1;expand:False;children:null,
  			name:3A2;expand:True;children:null,
  			name:3A3;expand:False;children:null
  		],
  		name:3A1;expand:False;children:null,
  		name:3A2;expand:False;children:null
  	]
    
*/