我想编写一个函数,该函数接受序列<1,1,2,2,3>并返回具有相等元素的序列,这些元素的分组方式类似于<< 1,1>,<2,2>,<3> >。
我使用的是序列,而不是列表,但是其中一些功能是相似的。我正在考虑使用的某些功能是映射,缩小,制表,过滤,附加等。
Reduce接受一个关联函数,并返回该运算符“减少”的序列。因此,降低op + 0 <1,2,3> = 6。
我的第一个想法是使用map将序列提升一个级别。 因此,<1,1,2,2,3> => << 1>,<1>,<2>,<2>,<3 >>。
然后,我正在考虑使用reduce,在该方法中,我创建了一个函数,该函数接受像(x,y)这样的成对元素。如果x == y,则返回其他值,则不执行任何操作。但是...这并不完全有效,因为函数在两种情况下都必须返回相同类型的东西。
有人可以给我一些正确使用方法的提示,例如我可以使用的更高阶函数吗?我正在使用SML,但我并没有要求任何人给我一个完整的答案,因此(使用任何一种功能性语言坦诚地说)任何高级技巧都将不胜感激
答案 0 :(得分:3)
我猜您所指的reduce
函数与F#中的fold
函数相同:
val fold : ('State -> 'Value -> 'State) -> 'State -> 'Value list -> 'State
这将获取一个值列表,以及一个初始状态和一个在迭代列表值时转换状态的函数。
您可以一次完成自己想做的事情。您需要保持一些状态。假设您在1,1,2,2,3
的中间(例如,在第二个2
上)。现在您需要:
2
[2]
(序列中的第一个2
)[ [1; 1] ]
。您将从初始状态-1, [], []
开始(使用-1
作为输入中不会出现的某些值)。然后,您需要编写根据当前值转换状态的函数。这需要处理几种情况:
希望这能为您提供足够的信息,以找出如何执行此操作,而无需实际透露完整的源代码!
答案 1 :(得分:2)
如果F#是您的语言,只需使用Seq.groupBy
function:
input |> Seq.groupBy id |> Seq.map snd
否则,
我假设您的语言支持Seq.distinct
,Seq.fold
,Seq.map
和Seq.init
。这些功能的F#版本可以在此document中找到。
然后您可以执行以下步骤:
1)使用Seq.distinct
对输入序列进行不同的序列:
input |> Seq.distinct
2)编写一个函数,该函数通过使用Seq.fold
计算一个序列中某个值出现的次数:
let count x theSeq =
theSeq
|> Seq.fold (fun n e -> if x = e then n+1 else n) 0
3)使用count
函数用输入序列中出现的次数来装饰不同序列的每个元素:
Seq.map (fun x -> (x, count x input))
4)最后,使用Seq.init
复制相等的元素:
Seq.map (fun (x, count) -> Seq.init count (fun i -> x))
整个代码:
let count x theSeq =
theSeq
|> Seq.fold (fun n e -> if x = e then n+1 else n) 0
input
|> Seq.distinct
|> Seq.map (fun x -> (x, count x input))
|> Seq.map (fun (x, count) -> Seq.init count (fun i -> x))
答案 2 :(得分:0)
不知道您使用的语言,但是从功能角度来看,我会:
伪代码:
originalSequence = <1,1,2,2,3>
distinctSequence = originalSequnce.distinct() // <1,2,3>
result = distinctSequence.map(elem => originalSequence.filter(e == elem)) // <<1,1>, <2, 2>, <3>>
答案 3 :(得分:0)
在Haskell中,您有group
和groupBy
。它们由名为span
的辅助函数制成。不幸的是,标准ML没有这么丰富的标准库,因此您必须自己创建函数。但是您可以使用相同的方法:
定义一个函数span
,该函数将列表分成两部分,第一部分是某些谓词为真的最长前缀,第二部分是列表的其余部分。
fun span p [] = ...
| span p (x::xs) = ... if p x then ... else ...
例如,
- span (fn n => n <= 3) [2,3,4,1,5]
> val it = ([2,3], [4,1,5])
这有点困难,因为您必须以某种方式将x
添加到递归调用span p xs
的结果中,即使它返回一对列表也是如此;所以你不能只写x :: span p xs
;您必须解开返回的货币对并返回(x :: ys, zs)
或(ys, x :: zs)
(一旦p x
为假,就停止递归)。
定义使用groupBy
的函数span
。 groupBy
使用的函数应该有两个参数,与span
接受一个参数的p
不同:第一个是要分组的元素,第二个是后续元素。 / p>
fun groupBy f [] = ...
| groupBy f (x::xs) = ... use span, f, x and xs to create (ys, zs) ...
... ys is the first group ...
... groupBy f zs is the remaining groups ...
如果函数f
处于咖喱状态(即类型为
'a -> 'a -> bool
因为它可以像val (ys, zs) = span (f x) xs
那样使用。
如果您想使用此方法,请随时提出后续问题。