C#用链式方法表达循环嵌套

一.起缘

故事缘于一位朋友的一道题:

朋友四人玩LOL游戏。第一局,分别选择位置:中单,上单,ADC,辅助;第二局新加入的伙伴要选上单,四人可选位置变为:中单,打野,ADC,辅助;要求,第二局四人每人不得选择和第一局相同的位置,请问两局综合考虑有多少种位置选择方式?

对于像我这边不懂游戏的人来讲,看不懂。于是有了这个版本:

有4个人,4只椅子,第一局每人坐一只椅子,第二局去掉第2只椅子,增加第5只椅子,每人坐一只椅子,而且每个人不能与第一局坐相同的椅子。问两局综合考虑,共有多少种可能的情况?

我一开始的想法是这样的,4个人就叫ABCD:第1局可能数是4*3*2*1=24,如果A第1局选了第2张椅,则A有4种可能,否则A有3种可能。对B来讲,如果A选了B第一局的椅,则B有3种可能,否则B有2种可能(排队自己第一局和A第二局已选)……想到这里我就晕了,情况越分越多。

二.原始的for嵌套

本来是一道数学题,应该由知识算出来有多少种,但我突然有个想法,不如用计算机穷举出出来。一来可以为各种猜测提供一个正确的答案,二来或许可以从答案反推出(数学上的)计算方法。然后就写了第1版:

static Seat data = new Seat();
public static void Run()
{
for (int a = 0; a < 4; a++)
{
if (data.IsSelected(0, a)) //第1局编号0。如果已经被人坐了。
continue;
data.Selected(0, a, "A"); //第1局编号0。A坐a椅。
for (int b = 0; b < 4; b++)
{
if (data.IsSelected(0, b))
continue;
data.Selected(0, b, "B");
for (int c = 0; c < 4; c++)
{
if (data.IsSelected(0, c))
continue;
data.Selected(0, c, "C");
for (int d = 0; d < 4; d++)
{
if (data.IsSelected(0, d))
continue;
data.Selected(0, d, "D");
for (int a2 = 0; a2 < 5; a2++)
{
if (a2 == 1)
continue;
if (data.IsSelected(1, a2)) //第2局编号1
continue;
if (data.IsSelected(0, a2, "A")) //如果第1局A坐了a2椅
continue;
data.Selected(1, a2, "A");
for (int b2 = 0; b2 < 5; b2++)
{
if (b2 == 1)
continue;
if (data.IsSelected(1, b2))
continue;
if (data.IsSelected(0, b2, "B"))
continue;
data.Selected(1, b2, "B");
for (int c2 = 0; c2 < 5; c2++)
{
if (c2 == 1)
continue;
if (data.IsSelected(1, c2))
continue;
if (data.IsSelected(0, c2, "C"))
continue;
data.Selected(1, c2, "C");
for (int d2 = 0; d2 < 5; d2++)
{
if (d2 == 1)
continue;
if (data.IsSelected(1, d2))
continue;
if (data.IsSelected(0, d2, "D"))
continue;
data.Selected(1, d2, "D");
data.Count++; //可能的情况数加1
Console.WriteLine("{0,5} {1}", data.Count, data.Current);
data.UnSelected(1, d2);
}
data.UnSelected(1, c2);
}
data.UnSelected(1, b2);
}
data.UnSelected(1, a2);
}
data.UnSelected(0, d);
}
data.UnSelected(0, c);
}
data.UnSelected(0, b);
}
data.UnSelected(0, a); //A起身(释放坐椅)
}
} 

部分运行结果:

说明:

1.ABCD是人名
2.“.”代表没有人
3.位置是是座位
4.-左边是第1局,右边是第2局
5.数字是序号

1 A B C D .-B . A C D
2 A B C D .-C . A B D
3 A B C D .-D . A B C
4 A B C D .-D . A C B
5 A B C D .-B . D A C
6 A B C D .-C . B A D
7 A B C D .-D . B A C
8 A B C D .-C . D A B
9 A B C D .-B . D C A
10 A B C D .-D . B C A
11 A B C D .-C . D B A
12 A B D C .-B . A D C
...
262 D C B A .-B . C D A
263 D C B A .-B . D C A
264 D C B A .-C . D B A

算出来是264种。从答案上来看是每11种是一组,一组中第1局的坐法是相同的,也就是说对于第一局的每一种情况,第2局都是有11种不同的可能。而第一局的可能性是24,所以答案是24*11=264。而第2局为什么是11种可能,后面再说。

三.想要链式写法

主题来了,像刚才的第1版的写法太死板太麻烦了。

如果能像这样写代码就爽了:

obj.Try("A").Try("B").Try("C").Try("D").Try2("A").Try2("B").Try2("C").Try2("D").Write(); 

而这样的代码通常的逻辑是执行Try("A")方法,然后执行Try("A")它return的对象的Try("B")方法……,即是Try("B")方法只被执行1次,而我希望的是Try("B")方法被Try("A")内部循环调用n次,Try("C")方法又被Try("B")方法调用m次。想想第1版的for套for不难明白为什么要追求这样的效果。如果Try("A")执行完了,再去执行Try("B"),那么Try("B")肯定不会被调用多次,所以得延迟Try("A")的执行,同理也延迟所有Try和Try2的执行。由于lambda表达天生有延迟计算的特性,于是很快写出了第2版:

public static void Run2()
{
Try("A",
() => Try("B",
() => Try("C",
() => Try("D",
() => Try2("A",
() => Try2("B",
() => Try2("C",
() => Try2("D",
null
)
)
)
)
)
)
)
);
}
public static void Try(string name, Action action) //第1局
{
for (int i = 0; i < 4; i++)
{
if (data.IsSelected(0, i))
continue;
data.Selected(0, i, name);
if (action == null)
{
Console.WriteLine(data.Current);
}
else
{
action();
}
data.UnSelected(0, i);
}
}
public static void Try2(string name, Action action) //第2局
{
for (int i = 0; i < 5; i++)
{
if (i == 1)
continue;
if (data.IsSelected(1, i))
continue;
if (data.IsSelected(0, i, name))
continue;
data.Selected(1, i, name);
if (action == null)
{
data.Count++;
Console.WriteLine("{0,5} {1}", data.Count, data.Current);
}
else
{
action();
}
data.UnSelected(1, i);
}
}

结构更合理,逻辑更清晰,但是一堆lambda嵌套,太丑了,也不是我要的效果,我要的是类似这样的:

obj.Try("A").Try("B").Try("C").Try("D").Try2("A").Try2("B").Try2("C").Try2("D").Write();

四.继续向目标逼近。

由于要延迟,所以必须先把要被调用的方法的引用“告诉”上一级,当上一级执行for的时候,就能调用下一级的方法。于是我想到了一个“回调链”

所以,执行链式方法是在构造回调链,最后的方法再通过调用链头(Head)的某个方法启动真正要执行的整个逻辑。

延迟计算是从Linq借鉴和学习来的,构造Linq的过程并没有执行,等到了执行ToList, First等方法时才真正去执行。

我想构造回调链每一步都是一个固定的方法,这里随便起用了T这个极短名称,而每一步后期计算时要执行的方法可灵活指定。于是有了第3版:

static Seat data = new Seat(); //借用Seat保存数据
public Seat2(string name, Seat2 parent, Action<Seat2> method)
{
this.Name = name;
this.Parent = parent;
if (parent != null)
parent.Child = this;
this.Method = method;
}
public static void Run()
{
new Seat2("A", null, me => me.Try())
.T("B", me => me.Try())
.T("C", me => me.Try())
.T("D", me => me.Try())
.T("A", me => me.Try2())
.T("B", me => me.Try2())
.T("C", me => me.Try2())
.T("D", me => me.Try2())
.P().Start();
}
public Seat2 T(string name, Action<Seat2> method)
{
return new Seat2(name, this, method);
}
public void Try()
{
for (int i = 0; i < 4; i++)
{
if (data.IsSelected(0, i))
continue;
data.Selected(0, i, this.Name);
if (this.Child != null)
{
this.Child.Method(this.Child);
}
data.UnSelected(0, i);
}
}
public void Try2()
{
for (int i = 0; i < 5; i++)
{
if (i == 1)
continue;
if (data.IsSelected(1, i))
continue;
if (data.IsSelected(0, i, this.Name))
continue;
data.Selected(1, i, this.Name);
if (this.Child != null)
{
this.Child.Method(this.Child);
}
data.UnSelected(1, i);
}
} 

五.解耦

这种调用方式,是满意了。但是运算框架与具体的算法耦合在一起,如果能把运算框架提取出来,以后写具体的算法也方便许多。于是经过苦逼的提取,测试,踩坑,最终出现了第4版:

//运算框架
class ComputeLink<T> where T : ISeat
{
ComputeLink<T> Parent { get; set; } //父节点,即上一级节点
ComputeLink<T> Child { get; set; } //子节点,即下一级节点
T Obj { get; set; } //当前节点对应的算法对象,可以看作业务对象
public ComputeLink(T obj, ComputeLink<T> parent, Action<T> method)
{
if (obj == null)
throw new ArgumentNullException("obj");
this.Obj = obj;
this.Obj.Method = x => method((T)x);
if (parent != null)
{
this.Parent = parent;
parent.Child = this;
parent.Obj.Child = this.Obj;
}
}
public static ComputeLink<T> New(T obj, Action<T> method)
{
return new ComputeLink<T>(obj, null, method);
}
public ComputeLink<T> Do(T obj, Action<T> method)
{
return new ComputeLink<T>(obj, this, method);
}
public ComputeLink<T> Head //链表的头
{
get
{
if (null != this.Parent)
return this.Parent.Head;
return this;
}
}
public void Action() //启动(延迟的)整个计算
{
var head = this.Head;
head.Obj.Method(head.Obj);
}
}
interface ISeat
{
ISeat Child { get; set; }
Action<ISeat> Method { get; set; }
}

p.s.为什么第4版是ISeat3而不是ISeat4呢,因为我本不把第1版当作1个版本,因为太原始了,出现第2版后,我就把第1版给删除了。为了写这篇文章才重新去写第1版。于是原本我当作第3版的ISeat3自然地排到了第4版。

具体的"算法"就很简单了:

class Seat3 : ISeat3
{
static Seat data = new Seat();
string Name { get; set; }
public Seat3(string name)
{
this.Name = name;
}
/// <summary>
/// 解耦的版本
/// </summary>
public static void Run()
{
var sql = ComputeLink<Seat3>
.New(new Seat3("A"), m => m.Try())
.Do(new Seat3("B"), m => m.Try())
.Do(new Seat3("C"), m => m.Try())
.Do(new Seat3("D"), m => m.Try())
.Do(new Seat3("A"), m => m.Try2())
.Do(new Seat3("B"), m => m.Try2())
.Do(new Seat3("C"), m => m.Try2())
.Do(new Seat3("D"), m => m.Try2())
.Do(new Seat3(""), m => m.Print());
sql.Action();
}
public Action<ISeat3> Method { get; set; }
public ISeat3 Child { get; set; }
public void Try()
{
for (int i = 0; i < 4; i++)
{
if (data.IsSelected(0, i))
continue;
data.Selected(0, i, this.Name);
if (this.Child != null)
{
this.Child.Method(this.Child);
}
data.UnSelected(0, i);
}
}
public void Try2()
{
for (int i = 0; i < 5; i++)
{
if (i == 1)
continue;
if (data.IsSelected(1, i))
continue;
if (data.IsSelected(0, i, this.Name))
continue;
data.Selected(1, i, this.Name);
if (this.Child != null)
{
this.Child.Method(this.Child);
}
data.UnSelected(1, i);
}
}
public void Print()
{
data.Count++;
Console.WriteLine("{0,5} {1}", data.Count, data.Current);
}
}

Seat3写起来简单,(Run方法内部)看起来舒服。通过链式写法达到嵌套循环的效果。对,这就是我要的!

它很像linq,所以我直接给变量命名为sql。

•对于Try和Try2来讲,要调用的方法最好从参数传来,但是这样就会增加Run方法中New和Do的参数复杂性,破坏了美感,所以经过权衡,Child和Method通过属性传入。这个我也不确定这样做好不好,请各位大侠指点。

•还有一个细节,就是ComputeLink构造方法中的(行号12的)代码 this.Obj.Method = x => method((T)x); 。我原来是这样写的 this.Obj.Method = method; 编译不通过,原因是不能把 Action<ISeat3> 转化为 Action<T> ,虽然T一定实现了ISeat3,强制转化也不行,想起以前看过的一篇文章里面提到希望C#以后的版本能拥有的一特性叫“协变”,很可能指的就是这个。既然这个 Action<ISeat3> 不能转化为 Action<T> 但是ISeat3是可以强制转化为T的,所以我包了一层薄薄的壳,成了 this.Obj.Method = x => method((T)x); ,如果有更好的办法请告诉我。

六.第2局为什么是11种可能

回过头来解决为什么对于一个确定的第1局,第2局有11种可能。

不妨假设第1局的选择是A选1号椅,B选2号椅,C选3号椅,D选4号椅。

第2局分为两大类情况:

如果B选了第5号椅

则只有2种可能:

A B C D .-D . A C B
A B C D .-C . D A B

如果B选了不是第5号椅,

则ACD都有可能选第5号椅,有3种可能。B有3种选的可能(1,3,4号椅),B一旦确定,A和C也只有一种可能

所以11 = 2 + 3 * 3

七.结论

由一道数学题牵引出多层循环嵌套,最终通过封装达到了我要的链式调用的效果,我是很满意的。这也是我第一次设计延迟计算,感觉强烈。如果新的场景需要用到延迟计算我想有了这次经验写起来会顺手许多。如果是需要多层for的算法题都可以比较方便的实现了。

你都看到这里了,为我点个赞吧,能说一下看法就更好了。

完整代码:

using System;
using System.Linq;
using System.Diagnostics;
namespace ConsoleApplication
{
class Seat
{
static Seat data = new Seat();
public static void Run()
{
//Seat.Run();
//return;
for (int a = ; a < ; a++)
{
if (data.IsSelected(, a)) //第局编号。如果已经被人坐了。
continue;
data.Selected(, a, "A"); //第局编号。A坐a椅。
for (int b = ; b < ; b++)
{
if (data.IsSelected(, b))
continue;
data.Selected(, b, "B");
for (int c = ; c < ; c++)
{
if (data.IsSelected(, c))
continue;
data.Selected(, c, "C");
for (int d = ; d < ; d++)
{
if (data.IsSelected(, d))
continue;
data.Selected(, d, "D");
for (int a = ; a < ; a++)
{
if (a == )
continue;
if (data.IsSelected(, a)) //第局编号
continue;
if (data.IsSelected(, a, "A")) //如果第局A坐了a椅
continue;
data.Selected(, a, "A");
for (int b = ; b < ; b++)
{
if (b == )
continue;
if (data.IsSelected(, b))
continue;
if (data.IsSelected(, b, "B"))
continue;
data.Selected(, b, "B");
for (int c = ; c < ; c++)
{
if (c == )
continue;
if (data.IsSelected(, c))
continue;
if (data.IsSelected(, c, "C"))
continue;
data.Selected(, c, "C");
for (int d = ; d < ; d++)
{
if (d == )
continue;
if (data.IsSelected(, d))
continue;
if (data.IsSelected(, d, "D"))
continue;
data.Selected(, d, "D");
data.Count++; //可能的情况数加
Console.WriteLine("{,} {}", data.Count, data.Current);
data.UnSelected(, d);
}
data.UnSelected(, c);
}
data.UnSelected(, b);
}
data.UnSelected(, a);
}
data.UnSelected(, d);
}
data.UnSelected(, c);
}
data.UnSelected(, b);
}
data.UnSelected(, a); //A起身(释放坐椅)
}
}
public static void Run()
{
Try("A",
() => Try("B",
() => Try("C",
() => Try("D",
() => Try("A",
() => Try("B",
() => Try("C",
() => Try("D",
null
)
)
)
)
)
)
)
);
}
public static void Try(string name, Action action)
{
for (int i = ; i < ; i++)
{
if (data.IsSelected(, i))
continue;
data.Selected(, i, name);
if (action == null)
{
Console.WriteLine(data.Current);
}
else
{
action();
}
data.UnSelected(, i);
}
}
public static void Try(string name, Action action)
{
for (int i = ; i < ; i++)
{
if (i == )
continue;
if (data.IsSelected(, i))
continue;
if (data.IsSelected(, i, name))
continue;
data.Selected(, i, name);
if (action == null)
{
data.Count++;
Console.WriteLine("{,} {}", data.Count, data.Current);
}
else
{
action();
}
data.UnSelected(, i);
}
}
public Seat()
{
seats[, ] = ".";
seats[, ] = ".";
}
private string[,] seats = new string[, ];
public void UnSelected(int game, int i)
{
Debug.Assert(game == && i != || game == && i != );
Debug.Assert(seats[game, i] != null);
seats[game, i] = null;
}
public void Selected(int game, int i, string name)
{
Debug.Assert(game == && i != || game == && i != );
Debug.Assert(seats[game, i] == null);
seats[game, i] = name;
}
public bool IsSelected(int game, int a)
{
return seats[game, a] != null && seats[game, a] != ".";
}
public bool IsSelected(int game, int a, string name)
{
return seats[game, a] == name;
}
public string Current
{
get
{
return string.Format("{} {} {} {} {}-{} {} {} {} {}",
seats[, ], seats[, ], seats[, ], seats[, ], seats[, ],
seats[, ], seats[, ], seats[, ], seats[, ], seats[, ]);
}
}
public int Count { get; set; }
}
class Seat
{
static Seat data = new Seat(); //借用Seat保存法的数据
Seat Parent { get; set; }
Seat Child { get; set; }
string Name { get; set; }
Action<Seat> Method { get; set; }
public Seat(string name, Seat parent, Action<Seat> method)
{
this.Name = name;
this.Parent = parent;
if (parent != null)
parent.Child = this;
this.Method = method;
}
/// <summary>
/// 耦合的版本
/// </summary>
public static void Run()
{
new Seat("A", null, me => me.Try())
.T("B", me => me.Try())
.T("C", me => me.Try())
.T("D", me => me.Try())
.T("A", me => me.Try())
.T("B", me => me.Try())
.T("C", me => me.Try())
.T("D", me => me.Try())
.P().Start();
}
public Seat T(string name, Action<Seat> method)
{
return new Seat(name, this, method);
}
public Seat P()
{
return new Seat("Print", this, me => me.Print());
}
public void Start()
{
var head = this.Head;
head.Method(head);
}
public Seat Head
{
get
{
if (null != this.Parent)
return this.Parent.Head;
return this;
}
}
public void Try()
{
for (int i = ; i < ; i++)
{
if (data.IsSelected(, i))
continue;
data.Selected(, i, this.Name);
if (this.Child != null)
{
this.Child.Method(this.Child);
}
data.UnSelected(, i);
}
}
public void Try()
{
for (int i = ; i < ; i++)
{
if (i == )
continue;
if (data.IsSelected(, i))
continue;
if (data.IsSelected(, i, this.Name))
continue;
data.Selected(, i, this.Name);
if (this.Child != null)
{
this.Child.Method(this.Child);
}
data.UnSelected(, i);
}
}
public void Print()
{
data.Count++;
Console.WriteLine("{,} {}", data.Count, data.Current);
}
public override string ToString()
{
return this.Name.ToString();
}
}
class ComputeLink<T> where T : ISeat
{
ComputeLink<T> Parent { get; set; } //父节点,即上一级节点
ComputeLink<T> Child { get; set; } //子节点,即下一级节点
T Obj { get; set; } //当前节点对应的算法对象,可以看作业务对象
public ComputeLink(T obj, ComputeLink<T> parent, Action<T> method)
{
if (obj == null)
throw new ArgumentNullException("obj");
this.Obj = obj;
this.Obj.Method = x => method((T)x);
if (parent != null)
{
this.Parent = parent;
parent.Child = this;
parent.Obj.Child = this.Obj;
}
}
public static ComputeLink<T> New(T obj, Action<T> method)
{
return new ComputeLink<T>(obj, null, method);
}
public ComputeLink<T> Do(T obj, Action<T> method)
{
return new ComputeLink<T>(obj, this, method);
}
public ComputeLink<T> Head //链表的头
{
get
{
if (null != this.Parent)
return this.Parent.Head;
return this;
}
}
public void Action() //启动(延迟的)整个计算
{
var head = this.Head;
head.Obj.Method(head.Obj);
}
}
interface ISeat
{
ISeat Child { get; set; }
Action<ISeat> Method { get; set; }
}
class Seat : ISeat
{
static Seat data = new Seat();
string Name { get; set; }
public Seat(string name)
{
this.Name = name;
}
/// <summary>
/// 解耦的版本
/// </summary>
public static void Run()
{
var sql = ComputeLink<Seat>
.New(new Seat("A"), m => m.Try())
.Do(new Seat("B"), m => m.Try())
.Do(new Seat("C"), m => m.Try())
.Do(new Seat("D"), m => m.Try())
.Do(new Seat("A"), m => m.Try())
.Do(new Seat("B"), m => m.Try())
.Do(new Seat("C"), m => m.Try())
.Do(new Seat("D"), m => m.Try())
.Do(new Seat(""), m => m.Print());
sql.Action();
}
public Action<ISeat> Method { get; set; }
public ISeat Child { get; set; }
public void Try()
{
for (int i = ; i < ; i++)
{
if (data.IsSelected(, i))
continue;
data.Selected(, i, this.Name);
if (this.Child != null)
{
this.Child.Method(this.Child);
}
data.UnSelected(, i);
}
}
public void Try()
{
for (int i = ; i < ; i++)
{
if (i == )
continue;
if (data.IsSelected(, i))
continue;
if (data.IsSelected(, i, this.Name))
continue;
data.Selected(, i, this.Name);
if (this.Child != null)
{
this.Child.Method(this.Child);
}
data.UnSelected(, i);
}
}
public void Print()
{
data.Count++;
Console.WriteLine("{,} {}", data.Count, data.Current);
}
public override string ToString()
{
return this.Name.ToString();
}
}
}

以上内容是小编给大家介绍的C#用链式方法表达循环嵌套的相关知识,希望对大家有所帮助!

(0)

相关推荐

  • C++中实现队列类链式存储与栈类链式存储的代码示例

    队列类链式存储 代码: linkqueue.hpp // 队列类 #pragma once #include "linklist.hpp" template <typename T> class LinkQueue { public: LinkQueue(); ~LinkQueue(); public: int clear(); int append(T &t); int retieve(T &t); int header(T &t); int le

  • smarty的section嵌套循环用法示例

    本文实例讲述了smarty的section嵌套循环用法.分享给大家供大家参考,具体如下: {section name="sec1" loop=$typeList} <TABLE class=left20 height=25 cellSpacing=0 cellPadding=0 width=624 background=images/indexbg.gif border=0> <TBODY> <TR> <TD class=zi align=le

  • 探讨:C++实现链式二叉树(用非递归方式先序,中序,后序遍历二叉树)

    如有不足之处,还望指正! 复制代码 代码如下: // BinaryTree.cpp : 定义控制台应用程序的入口点.//C++实现链式二叉树,采用非递归的方式先序,中序,后序遍历二叉树#include "stdafx.h"#include<iostream>#include<string>#include <stack>using namespace std;template<class T>struct BiNode{ T data; 

  • 用C++实现一个链式栈的实例代码

    自定义一个链式栈,c++语言实现,不足之处,还望指正! 复制代码 代码如下: // MyStack.cpp : 定义控制台应用程序的入口点.//自己构造一个链式栈,具有push(入栈),pop(出栈),top(取得栈顶元素),size(返回栈大小),empty(判断是否为空)等功能#include "stdafx.h"#include <iostream>using namespace std;//构造栈的节点template <class T>struct N

  • 解析C++的线性表链式存储设计与相关的API实现

    基本概念 链式存储定义: 为了表示每个数据元素与其直接后继元素之间的逻辑关系,每个元素除了存储本身的信息外,还需要存储指示其直接后继的信息. 表头结点: 链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息. 数据结点: 链表中代表数据元素的结点,包含指向下一个数据元素的指针和数据元素的信息. 尾结点: 链表中的最后一个数据结点,其下一元素指针为空,表示无后继. 链表技术领域推演 链表链式存储_api实现分析: 在C语言中可以用结构体来定义链表中的指针域,链表中的表头结点也可以

  • 讲解C++的do while循环和循环语句的嵌套使用方法

    用do-while语句构成循环 do-while语句的特点是先执行循环体,然后判断循环条件是否成立.其一般形式为: do 语句 while (表达式); 它是这样执行的:先执行一次指定的语句(即循环体),然后判别表达式,当表达式的值为非零("真") 时,返回重新执行循环体语句,如此反复,直到表达式的值等于0为止,此时循环结束.可以用下图表示其流程. [例]用do-while语句求1+2+3+-+100. #include <iostream> using namespace

  • C#用链式方法表达循环嵌套

    一.起缘 故事缘于一位朋友的一道题: 朋友四人玩LOL游戏.第一局,分别选择位置:中单,上单,ADC,辅助:第二局新加入的伙伴要选上单,四人可选位置变为:中单,打野,ADC,辅助:要求,第二局四人每人不得选择和第一局相同的位置,请问两局综合考虑有多少种位置选择方式? 对于像我这边不懂游戏的人来讲,看不懂.于是有了这个版本: 有4个人,4只椅子,第一局每人坐一只椅子,第二局去掉第2只椅子,增加第5只椅子,每人坐一只椅子,而且每个人不能与第一局坐相同的椅子.问两局综合考虑,共有多少种可能的情况? 我

  • JavaScript使用链式方法封装jQuery中CSS()方法示例

    本文实例讲述了JavaScript使用链式方法封装jQuery中CSS()方法.分享给大家供大家参考,具体如下: 主要思路就是:返回this对象,将所获取的操作元素放入一个数组中.在原型中添加拓展方法 <html> <head> <title></title> </head> <body> <div id="one">aa</div> </body> <script typ

  • 如何利用扩展方法来链式的对MVC 3中的页面进行验证

    .Net 3.0 添加了一个语法糖就是扩展方法,其实扩展方法的本质就是对类的静态方法的调用,虽然扩展方法只是改变了我们写代码的方式,但是如果我们使用得当,可以给我们带来巨大的编码效率的提升.对于C#扩展方法的使用,我就不细说了,贴段代码说明扩展方法的使用,大家就会回忆起来. 复制代码 代码如下: public static class Extensions { public static string EndWith(this string str) { return str + "@"

  • PHP实现链式操作的核心思想

    PHP 链式操作的实现 复制代码 代码如下: $db->where()->limit()->order(); 在 Common 下创建 Database.php. 链式操作最核心的地方在于:在方法的最后 return $this; Database.php: <?php namespace Common; class Database{ function where($where){ return $this; //链式方法最核心的地方在于:在每一个方法之后 return $thi

  • java队列实现方法(顺序队列,链式队列,循环队列)

    双向顺序队列ArrayDeque和双向链式队列LinkedList,JDK已经包含,在此略.ArrayDeque包括顺序栈和顺序队列,LinkedList包含链式栈和链式队列.ArrayDeque和LinkedList都是线程不安全的.PriorityQueue优先队列也在JDK. 1.顺序队列的实现 package lang; import java.io.Serializable; import java.util.Arrays; /** * @ClassName: ArrayQueue *

  • C++实现循环队列和链式队列的示例

    循环队列: 1.循环队列中判断队空的方法是判断front==rear,队满的方法是判断front=(rear+1)%maxSize.(我曾经想过为什么不用一个length表示队长,当length==maxSize时队满)原因就是,在频繁的队列操作中,多出一个变量会大量的增加执行时间,所以不如浪费一个数组空间来得划算. 2.用单链表表示的链式队列特别适合于数据元素变动较大的情形,而且不存在溢出的情况. template<class T> class SeqQueue{ protected: T

  • js实现封装jQuery的简单方法与链式操作详解

    我用这篇文章来理一理如何用js去实现封装jQuery的简单方法. 本文js实现了下面jquery的几种方法,我将它分为8个小目标 实现$(".box1").click( )方法 实现$("div").click( )方法 考虑$( )中参数的三种情况 实现jq中的on方法 实现链式操作 实现jq中的eq方法 实现jq中的end方法 实现jq中的css方法 有不正确的地方还望大家在评论区指出来,谢谢啦. 1. 实现$(".box1").click(

  • JS实现线性表的链式表示方法示例【经典数据结构】

    本文实例讲述了JS实现线性表的链式表示方法.分享给大家供大家参考,具体如下: 从上一节可以,顺序存储结构的弱点就是在插入或删除操作时,需要移动大量元素.所以这里需要介绍一下链式存储结构,由于它不要求逻辑上相邻的元素在物理位置上也相邻,所以它没有顺序存储结构的弱点,但是也没有顺序表可随机存取的优点. 下面介绍一下什么是链表. 线性表的链式存储结构用一组任意的存储单元存储线性表的数据元素.所以,每一个数据元素除了存储自身的信息之外,还需要存储一个指向其后继的存储位置的信息.这两部分信息组成了元素的存

  • php类自动装载、链式操作、魔术方法实现代码

    1.自动装载实例 目录下有3个文件:index.php load.php tests文件夹 tests文件夹里有 test1.php <?php namespace Tests; class Test1{ static function test(){ echo __CLASS__.'<br>'; echo __FILE__.'<br>'; } } index.php内容 <?php include "load.php"; Tests\Test1::

  • PHP实现链式操作的三种方法详解

    本文实例讲述了PHP实现链式操作的三种方法.分享给大家供大家参考,具体如下: 在php中有很多字符串函数,例如要先过滤字符串收尾的空格,再求出其长度,一般的写法是: strlen(trim($str)) 如果要实现类似js中的链式操作,比如像下面这样应该怎么写? $str->trim()->strlen() 下面分别用三种方式来实现: 方法一.使用魔法函数__call结合call_user_func来实现 思想:首先定义一个字符串类StringHelper,构造函数直接赋值value,然后链式

随机推荐