温馨提示:本文翻译自stackoverflow.com,查看原文请点击:其他 - how to keep only 'stable' values in a list in F#
f#

其他 - 如何在F#的列表中仅保留“稳定”值

发布于 2020-04-08 10:52:05

我有以下数据:

[0,+ 1,+ 1,+ 1、0,+ 1,-1,-1、0,-1,-1,-1,-1,+ 1,+ 1,+ 1,-1,+ 1,+ 1,+1,+1,+1,+1,+1,0]

这是我想要的输出:

[0,+ 1,+ 1,+ 1、0、0、0、0、0,-1,-1,-1,-1、0、0、0,+ 1,+ 1,+ 1,+ 1,+1,+1,+1,0]

在源列中,数据可以为+ 1,-1或0。

在输出中,具有3个或更多顺序出现的+1和-1s可以保留;那些没有的,必须转换为0。

Python / Pandas实现是这样的:

s = df[data].where(df[data].groupby(df[data].ne(df[data].shift()).cumsum()).transform('size').ge(3), 0)

如何在F#中实现呢?

查看更多

提问者
Thomas
被浏览
60
Tomas Petricek 2020-01-31 08:23

我认为没有使用内置F#函数执行此操作的简便方法。但是,如果定义一个助手操作,则可以很好地解决此问题。

我将调用该辅助函数,该函数groupAdjacentBy根据一些计算分组键的函数将列表中的相邻元素分组在一起。就像一样List.groupBy,不同之处在于它只对具有相同键的元素进行分组,只要它们彼此相邻即可。

val groupAdjacentBy : ('a -> 'b) -> 'a list -> 'a list list 

F#列表的此实现如下所示:

module List =
  let groupAdjacentBy f list = 
    let rec loop k group acc list = 
      match list with 
      | [] when List.isEmpty group -> List.rev acc
      | [] -> List.rev ((List.rev group)::acc)
      | x::xs when f x = k -> loop k (x::group) acc xs 
      | x::xs when not (List.isEmpty group) -> loop (f x) [x] ((List.rev group)::acc) xs
      | x::xs -> loop (f x) [x] [] xs
    if List.isEmpty list then []
    else loop (f (List.head list)) [List.head list] [] (List.tail list)

现在,您可以通过对具有相同值的相邻元素进行分组并将所有小于3的组替换为长度相等且包含零的组来解决原始问题:

[ 0; +1; +1; +1; 0; +1; -1; -1; 0; -1; -1; -1; -1; 
  +1; +1; -1; +1; +1; +1; +1; +1; +1; +1; 0]
|> List.groupAdjacentBy id
|> List.map (fun group ->
  if List.length group >= 3 then group
  else List.map (fun _ -> 0) group)
|> List.concat