提供3000多款全球软件/控件产品
针对软件研发的各个阶段提供专业培训与技术咨询
根据客户需求提供定制化的软件开发服务
全球知名设计软件,显著提升设计质量
打造以经营为中心,实现生产过程透明化管理
帮助企业合理产能分配,提高资源利用率
快速打造数字化生产线,实现全流程追溯
生产过程精准追溯,满足企业合规要求
以六西格玛为理论基础,实现产品质量全数字化管理
通过大屏电子看板,实现车间透明化管理
对设备进行全生命周期管理,提高设备综合利用率
实现设备数据的实时采集与监控
利用数字化技术提升油气勘探的效率和成功率
钻井计划优化、实时监控和风险评估
提供业务洞察与决策支持实现数据驱动决策
翻译|使用教程|编辑:王香|2018-10-11 09:30:13.000|阅读 521 次
概述:通过扑克自牌游戏评分游戏来概述使用LINQ对这些集合进行排序和过滤。
# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>
相关链接:
【下载Telerik UI for ASP.NET AJAX最新版本】
在面向对象编程(OOP)中,我们习惯于使用对象集合或简单数据类型。我们经常使用LINQ对这些集合进行排序和过滤,作为业务逻辑行为或数据转换的一部分。虽然这些是我们经常执行的有用任务,但很容易忘记C#中的函数可以被视为数据。如果我们重新考虑作为数据的函数思考,它使我们能够发现OOP中标准问题的替代解决方案。
在本文中,我们将看一下C#Functional Programming研讨会的一个例子。该场景概述了用于对扑克牌进行评分的解决方案。我们将研究一种利用函数作为数据的解决方案的替代模式。通过这种新模式,我们将为游戏的评分机制提供灵活性。
首先,让我们来看看用于产生最终得分的各个评分函数。每个功能都是一个规则,用于确定手牌是否符合标准。
private bool HasFlush(IEnumerable<Card> cards) => ...; private bool HasRoyalFlush(IEnumerable<Card> cards) => ...; private bool HasPair(IEnumerable<Card> cards) => ...; private bool HasThreeOfAKind(IEnumerable<Card> cards) => ...; private bool HasFourOfAKind(IEnumerable<Card> cards) => ...; private bool HasFullHouse(IEnumerable<Card> cards) => ...; private bool HasStraightFlush(IEnumerable<Card> cards) => ...; private bool HasStraight(IEnumerable<Card> cards) => ...;
下图说明了游戏得分的规则。虽然这些函数表明手是否符合标准,但它们不会直接影响手的最终得分。我们需要安排规则并按重要性评估它们以产生分数并将其分配给HandRank的枚举型数据。
使用规则,我们可以通过几种不同的方式确定最终得分值。以下每个示例在技术上都是正确的,并提供其自身的可读性和简单性。每种方法的消极方面是规则执行的顺序是“hard coded”。
这种评估分数的方法使用临时占位符值来跟踪分数。每次评估都会进行,score并使用最好的HandRank进行更新。此方法非常明确,但涉及完成任务所不需要的额外代码和变量。
public HandRank GetScore(Hand hand) { var score = HandRank.HighCard; if (HasPair(hand.Cards)) { score = HandRank.Pair; } ... if (HasRoyalFlush(hand.Cards)) { score = HandRank.RoyalFlush; } return score; }
使用返回早期模式允许我们编写直观的代码,通过在发现评估为真时立即从函数返回来返回最佳HandRank。由于应用程序需要新规则,因此该方法易于阅读且易于修改。
public HandRank GetScore(Hand hand) { if (HasRoyalFlush()) return HandRank.RoyalFlush; ... if (HasPair()) return HandRank.Pair; return HandRank.HighCard; }
可以使用三元运算符将函数写为单个表达式。这与返回早期方法具有类似的效果,但代码更少。对于某些人来说,这种方法的可读性可能比其他人更容易。
在所有前面的例子中,操作顺序是至关重要的。如果我们决定在此评分函数中添加新规则,那么我们需要确保以正确的顺序插入它们以确定正确的分数。
GetScore操作正逐步完成标准评估,并将结果为true的第一个规则与匹配的HandRank匹配。我们可以从函数式编程思维方式中解决问题,而不是将函数作为单独的语句进行评估。让我们通过将函数视为数据来改变我们对问题的看法。
如果我们将各个评分函数看作数据,我们就可以识别出一种模式。考虑以下评分函数的signature。
private bool HasFlush(IEnumerable<Card> cards) => ...; private bool HasRoyalFlush(IEnumerable<Card> cards) => ...; private bool HasPair(IEnumerable<Card> cards) => ...; private bool HasThreeOfAKind(IEnumerable<Card> cards) => ...; private bool HasFourOfAKind(IEnumerable<Card> cards) => ...; private bool HasFullHouse(IEnumerable<Card> cards) => ...; private bool HasStraightFlush(IEnumerable<Card> cards) => ...; private bool HasStraight(IEnumerable<Card> cards) => ...;
每个功能都属于同一类型Func, bool>。由于我们有许多相同类型的数据,我们可以将它们安排在一个集合或数组中。接下来,我们需要将每个函数与它所代表的HandRank相匹配。例如:HasPair将得分为HandRank.Pair。使用元组,我们可以轻松创建此映射,而无需专门的类。在C#7.1中,我们可以通过简单地在括号中包含多个值来创建元组。使用函数及其映射的枚举器,我们可以构建集合。
private List<(Func<IEnumerable<Card>, bool> eval, HandRank rank)> GameRules() => new List<(Func<IEnumerable<Card>, bool> eval, HandRank rank)> { (cards => HasRoyalFlush(cards), HandRank.RoyalFlush), (cards => HasStraightFlush(cards), HandRank.StraightFlush), (cards => HasFourOfAKind(cards), HandRank.FourOfAKind), (cards => HasFullHouse(cards), HandRank.FullHouse), (cards => HasFlush(cards), HandRank.Flush), (cards => HasStraight(cards), HandRank.Straight), (cards => HasThreeOfAKind(cards), HandRank.ThreeOfAKind), (cards => HasPair(cards), HandRank.Pair), (cards => true, HandRank.HighCard), };
为了保持代码整洁,我们将把集合的构造包装在一个名为GameRules的函数中。我们以后可以将其作为其他游戏规则的可扩展点。通过将排名系统移到GetScore方法之外,可以修改或替换新的评估和排名。对于可能的最低排名,我们将简单地使用true来表示默认评估。
现在我们将使用LINQ重写GetScore方法来评估列表。通过将列表中的项目视为数据,我们可以利用排序来确保它们以正确的顺序执行。我们不再需要担心“硬编码”执行顺序。我们可以使用.OrderByDescending(card => card.rank)将评估从最强等级排序到最弱,因为HandRank.RoyalFlush具有最高值。
public HandRank GetScore(Hand hand) => GameRules() .OrderByDescending(rule => rule.rank) .First(rule => rule..rank;
最后,为了得到结果,我们将进行评估。最有效的方法是使用First LINQ方法。由于First是短路运算符,因此只要找到返回true的第一个项目,它就会停止对项目进行评估。当第一项计算结果为true时,我们将从数据集中获取元组的排名值并返回它。排名值是我们的最终得分。
C#中的函数通常被认为是静态语句,我们的应用程序可以使用它来更改系统中的数据状态。通过将我们的观点从命令性转变为功能性,我们可以找到替代解决方案。为问题带来功能性思维的一种方法是记住函数也是数据,并且符合许多与C#中其他数据类型相同的规则。在这个例子中,我们看到了一种功能方法如何将基于语句的硬编码评估转换为灵活的排序和基于地图的评估。这个简单的更改扩展了应用程序的功能,并在添加新条件时减少了摩擦,因为没有预定义操作顺序。
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn
本文探讨 SQL Server 中 NULL 和空值之间的区别,并讨论如何有效地处理它们。
Unity 是一款功能极其丰富的游戏引擎,允许开发人员将各种媒体集成到他们的项目中。但是,它缺少最令人兴奋的功能之一 - 将 Web 内容(例如 HTML、CSS 和 JavaScript)直接渲染到 3D 场景中的纹理上的能力。在本文中,我们将介绍如何使用 DotNetBrowser 在 Unity3D 中将 Web 内容渲染为纹理。
DevExpress v24.2帮助文档正式发布上线了,请按版本按需下载~
本教程将向您展示如何用MyEclipse构建一个Web项目,欢迎下载最新版IDE体验!
主要针对专业级的ASP.NET AJAX开发,拥有构建ASP.NET AJAX和SharePoint应用程序的80+控件。
服务电话
重庆/ 023-68661681
华东/ 13452821722
华南/ 18100878085
华北/ 17347785263
客户支持
技术支持咨询服务
服务热线:400-700-1020
邮箱:sales@pclwef.cn
关注我们
地址 : 重庆市九龙坡区火炬大道69号6幢