当命令性地编程时,我经常发现自己将代码编写到这样的组中:
function group(items):
groups <- new Groups
curGroup <- new Group
for item in items:
if item doesn't belong in curGroup:
if curGroup is good:
add curGroup to groups
curGroup <- new Group
add item to curGroup
if curGroup is good:
add curGroup to groups
return groups
不幸的是,这段代码存在一些不足之处:
if curGroup is good: add curGroup to groups
代码重复。虽然条件中的条件可以分解为函数,但调用该函数并将curGroups添加到组的逻辑仍会出现两次,并且很容易忘记第二次出现。
创建新组的逻辑出现两次。这个逻辑可能很简单,如果不是那么它可以分解成一个单独的函数,但与第一个项目符号点一样,它表示流程不正确。
第一项可能无法通过归属检查,在这种情况下,我们会在创建新组后立即创建新组。此问题可能看似微不足道,但有时需要明确阻止将初始空组添加到groups
。无论如何,它表明了所需逻辑的错误表达。
我想知道是否有一种更清晰的方式来表达这种逻辑。我为这个问题的抽象性质道歉,但这个问题出现在多个上下文中。如果有必要在特定编程语言的上下文中解决此问题,则可以假设Java。
答案 0 :(得分:1)
解决此问题的一种方法是将is good
组过滤器从分组循环中拆分 - 将其视为后处理或需求驱动的过滤。您可以争辩说,将两者结合起来(如您的问题中所示)是过早优化导致尴尬代码的一个例子。
如果使用内部Group
循环对while item
进行外循环迭代,则可以自然地避免重复new Group
代码。它还应该有助于巧妙地处理您的第一项问题,方法是更容易对待组中的第一项与其他项不同:
function group(items):
groups <- new Groups
while(items not empty):
curGroup <- new Group
using items:
add current item to curGroup
advance to next item
while(items not empty):
using items:
if current item belongs in curGroup:
add current item to curGroup
advance to next item
else exit inner loop
if(curGroup is good):
add curGroup to groups
return groups
请注意,上面的伪代码使用items
作为迭代器。
即使您的问题是关于命令式编程,查看groupBy
的Haskell实现也许是有益的。
答案 1 :(得分:1)
我接近这个的方法是在你的第一个if
语句中添加一个附加条件,这样它就包含了最终if
语句的逻辑。如果该项目不属于当前群组,或者我位于curGroup
中的最后group
,我会确保将item
添加到items
。
这不是一个大规模的改进(它仍然是八行代码,我不喜欢奇怪的嵌套if
语句),但我无法想到更好的解决方案。
它很好地解决了你的三个问题:
if curGroup is good: add curGroup to groups
不再重复Group
添加Groups
也不再重复这可能是这样的:
function group(items):
groups <- new Groups
curGroup <- new Group
for item in items:
if item doesn't belong in curGroup || item is last item:
if item is last item:
add item to curGroup
if curGroup is good:
add curGroup to groups
curGroup <- new Group
add item to curGroup
return groups
我很高兴看到比这更好,更精致的解决方案,但我想我会发布这个至少让事情滚动
更新
这是一个不同的方向你可以采取这个(如果它在Java中工作,我更习惯于C#)。不是构建一组组,而是构建一个哈希映射(我将它称为字典,因为它就是C#中的内容),键是你计算的一些值来确定一个项属于哪个组,而值是一组项目。确定项目属于哪个组的功能应该与您当前检查项目是否属于当前gruop的方式非常相似。
然后你的代码看起来像这样:
function group(items):
groups <- new Dictionary<string, Group>
for item in items:
groupKey <- item.FindKey()
if !groups.ContainsKey(groupKey):
add new group to groups with key of groupKey
add item to groups[groupKey]
return groups
这种方法的优点:
缺点
FindKey
函数(虽然我怀疑它在大多数情况下都不会)