我有A,B和C类型的项目集合。 我想处理集合并交换所有A和B对,但如果有C(也是一个集合),我想以递归方式处理它。
所以
SELECT KaizenData.TrackingNumber, KaizenData.KaizenLevel, KaizenData.Plant, KaizenData.Year1, KaizenData.[Tracking No], KaizenData.MainPillar, KaizenData.Area AS Dept, KaizenData.Team AS Area, KaizenData.[OP/STA] AS [Machine/Station], KaizenData.ProjectName AS [Project Name], KaizenData.IssueDescription AS [Description Phenomena], KaizenData.SolutionDescription AS [Solution Description], KaizenData.[Project Board], KaizenData.[Loss Category], KaizenData.[Loss Type], KaizenData.EnteredDate AS [Entered Date], KaizenData.StartingDate AS [Starting Date], KaizenData.EndDate AS [Completion Data], KaizenData.[Wk Comp], KaizenData.Benefit, KaizenData.Cost, KaizenData.BC, KaizenData.Savings, IIf([closedstatus]=True,"Closed") AS Status
FROM KaizenData
WHERE (((IIf([closedstatus]=True,"Closed")) Is Not Null));
将被翻译成
#(A1 A2 B1 B2 A3 #(A4 A5 B3) )
交换不具有传递性,因此#(A1 B1 A2 B2 A3 #(A4 B3 A5) )
将被翻译为#(A1 B1 B2)
而非#(B1 A1 B2)
。
我想使用#(B1 B2 A1)
,但问题是第二个元素总是被处理两次。
这可以通过Collection API以某种方式实现,而无需使用原始的forloops吗?
我正在寻找可读性而非高效的解决方案。
答案 0 :(得分:1)
我认为我的解决方案应该做你想要的事情,但事先做了几点说明:
#overlappingPairsDo:
的实现,那就是他们所做的,而且因为你在pharo标签内提问,所以非常欢迎你贡献你对“Collections API”做一些有用的新方法,这样我们都可以从中受益。为了提供帮助,我添加了一个带有两个类方法的类SwapPairsDemo
。第一个只是一个帮助器,因为出于演示目的,我们使用了示例中的Array
个对象,它们包含ByteSymbol
个实例作为A
和B
我们希望与C
集合类型区分开的类型 - ByteSymbol
s当然是集合,所以让我们假装它们不仅仅是为了这个练习。
isRealCollection: anObject
^anObject isCollection
and: [anObject isString not
and: [anObject isSymbol not]]
第二种方法保存代码以显示交换并允许递归:
swapPairsIn: aCollection ifTypeA: isTypeABlock andTypeB: isTypeBBlock
| shouldSwapValues wasJustSwapped |
shouldSwapValues := OrderedCollection new: aCollection size - 1 withAll: false.
aCollection overlappingPairsWithIndexDo: [:firstItem :secondItem :eachIndex |
(self isRealCollection: firstItem)
ifTrue: [self swapPairsIn: firstItem ifTypeA: isTypeABlock andTypeB: isTypeBBlock]
ifFalse: [
shouldSwapValues at: eachIndex put: ((self isRealCollection: secondItem) not
and: [(isTypeABlock value: firstItem)
and: [isTypeBBlock value: secondItem]])
]
].
(self isRealCollection: aCollection last)
ifTrue: [self swapPairsIn: aCollection last ifTypeA: isTypeABlock andTypeB: isTypeBBlock].
wasJustSwapped := false.
shouldSwapValues withIndexDo: [:eachBoolean :eachIndex |
(eachBoolean and: [wasJustSwapped not])
ifTrue: [
aCollection swap: eachIndex with: eachIndex + 1.
wasJustSwapped := true
]
ifFalse: [wasJustSwapped := false]
]
这有点寥寥无几,我通常会重构一个这么大的方法,而且你可能想要处理零,空列表等等,但希望你能够找到解决问题的方法。该代码包含三个步骤:
overlappingPairsWithIndexDo:
进行迭代来构建一个集合(小于主集合大小的集合),以确定是否应该交换两个项目 。要运行代码,您需要提供集合以及判断事物是否为“A”或“B”的方式 - 我刚刚使用了您的示例,所以我只是问他们是否从这些字母开始 - 显然可以用任何适合你用例的东西代替。
| collection target isTypeA isTypeB |
collection := #(A1 A2 B1 B2 A3 #(A4 A5 B3) ).
target := #(A1 B1 A2 B2 A3 #(A4 B3 A5) ).
isTypeA := [:anItem | anItem beginsWith: 'A'].
isTypeB := [:anItem | anItem beginsWith: 'B'].
SwapPairsDemo swapPairsIn: collection ifTypeA: isTypeA andTypeB: isTypeB.
^collection = target
在工作区中检查此内容会返回true
,即collection
上的互换已经执行,现在它与target
相同。
答案 1 :(得分:0)
这是一个没有递归的解决方案,采用两步法:
result := OrderedCollection new.
#(1 3 4 6 7)
piecesCutWhere: [ :a :b | a even = b even ]
do: [ :run |
result addAll: ((result isEmpty or: [ result last even ~= run first even ])
ifTrue: [ run ]
ifFalse: [ run reverse ]) ].
result asArray = #(1 4 3 6 7) "--> true"
首先,我们在任何可能进行交换的地方拆分集合。然后,在第二步中,我们只交换结果集合的最后一个元素是否仍然允许交换。
向此添加递归应该是直截了当的。