如何将基于 LINQ 的代码重写为 for 循环
本文关键字:重写 代码 for 循环 LINQ | 更新日期: 2023-09-27 18:35:32
我使用以下代码:
public class Card
{
public Card(Rank rank, Suit suit)
{
this.Rank = rank;
this.Suit = suit;
}
public Rank Rank { get; private set; }
public Suit Suit { get; private set; }
}
public enum Rank : byte
{
Ace = 1,
Two = 2,
Three = 3,
Four = 4,
Five = 5,
Six = 6,
Seven = 7,
Eight = 8,
Nine = 9,
Ten = 10,
Jack = 11,
Queen = 12,
King = 13,
}
public enum Suit : byte
{
Club = 1, // Klavers
Diamond = 2, // Ruiten
Heart = 3, // Harten
Spades = 4 // Schoppen
}
public class Deck
{
private List<Card> deck = new List<Card>(52);
public Deck()
{
this.FillStack();
}
public void FillStack()
{
this.deck.Clear();
this.deck.AddRange(
Enumerable.Range(1,4)
.SelectMany( s =>
Enumerable.Range(1, 13)
.Select( n => new Card( (Rank)n , (Suit)s ) )
)
) ;
}
是否可以将 FillStack
中基于 LINQ 的代码替换为基于 for
循环的等效代码?目标是使代码更易于理解,并为不太熟悉 LINQ 的用户扩展。
是的,这看起来是一个很好的示例,说明如何使用 LINQ 帮助程序方法。与普通的旧且更具可读
性相比,没有任何优势for (int s = 1; s <= 4; s++)
for (int n = 1; n <= 13; n++)
this.deck.Add(new Card((Rank)n, (Suit)s));
不过,LINQ 版本可以提高可读性:下面是在不尝试将其全部填充到单个表达式中时的外观。
var suits = Enumerable.Range(1, 4);
var ranks = Enumerable.Range(1, 13);
var cards =
from s in suits
from n in ranks
select new Card((Rank)n, (Suit)s);
this.deck.AddRange(cards);
这应该更容易理解,但它仍然意味着几乎相同的事情。
你可以这样说
public void FillStack()
{
this.deck.Clear() ;
this.deck.AddRange(
Enumerable
.Range(0,52)
.Select( n => new Card( (Rank)(1+n%13), (Suit)(1+n/13) ) )
) ;
return ;
}
甚至
public void FillStack()
{
this.deck.Clear() ;
foreach ( Rank rank in Enum.GetValues(typeof(Rank)) )
{
foreach( Suit suit in Enum.GetValues(typeof(Suit)) )
{
Card card = new Card( rank , suit ) ;
this.deck.Add( card ) ;
}
}
return;
}
您的问题是将 LINQ 查询替换为 for 循环,以便更容易理解。这很公平。但是,由于您正在学习,因此值得了解查询本身。然后,您将能够自己更换它,或者更好的是,您将对它感到足够舒适,可以将其留在那里。
让我们分解它并尝试逐行解释它:
[1] this.deck
[2] .AddRange(
[3] Enumerable.Range(1, 4)
[4] .SelectMany(s =>
[5] Enumerable.Range(1, 13)
[6] .Select(n =>
[7] new Card((Rank)n, (Suit)s))));
从 #3 行开始 Enumerable.Range(1,4)
- 该方法返回从 1
到 4
的数字范围。所以我们有一个集合1, 2, 3, 4
.在第 #4 行中,我们逐项访问此集合。因此,我们实际上迭代了这些项目。每个项目都由变量s
表示 - 您可以使用它来访问项目。重复相同的机制以创建从 1 到 13 的迭代(行 #5 和 #6)。第二次迭代中的项由变量 n
访问。
更大的图景 - 我们从 1 迭代到 4,在内部我们从 1 迭代到 13。现在,在第 #7 行中,我们创建了一个Card
,并且两次迭代的数字(表示为 n
和 s
)都用于类的构造函数中。因为我们遍历从 1 到 4 的数字,在 1 到 13 的内部,我们将得到所有的组合:(1,1) (1,2) (1,3) (1,4) (2,1) (2,2) 等等。组合中的每个项目都将创建一张卡片。因此,这将导致卡片的集合。现在回到第 #2 行AddRange
该方法负责将此范围的卡片添加到deck
集合中。
希望这将有助于理解查询并将其替换为更命令式的代码。