Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List 替换列表元素是反模式吗?_List_F#_Anti Patterns - Fatal编程技术网

List 替换列表元素是反模式吗?

List 替换列表元素是反模式吗?,list,f#,anti-patterns,List,F#,Anti Patterns,我有一个模块,它在以列表表示的路径上工作。大多数函数都执行典型的递归列表处理,但现在我需要一个有时会改变路径的函数。因此,我编写了这个replace函数: module List = let replace f sub xs = let rec finish acc = function | [] -> acc | x::xs -> finish (x::acc) xs let rec search acc = function

我有一个模块,它在以列表表示的路径上工作。大多数函数都执行典型的递归列表处理,但现在我需要一个有时会改变路径的函数。因此,我编写了这个
replace
函数:

module List =
  let replace f sub xs = 
    let rec finish acc = function
      | [] -> acc
      | x::xs -> finish (x::acc) xs
    let rec search acc = function
      | [] -> None
      | x::xs -> 
        if f x then Some(finish ((sub x)::xs) acc)
        else search (x::acc) xs
    search [] xs

其工作原理如下:

let xs = List.init 10 id
let res = List.replace ((=) 5) (fun _ -> -1) xs
//Some [0; 1; 2; 3; 4; -1; 6; 7; 8; 9]

通常,当我觉得有必要扩充一个内置模块时,我最终会发现我在做一些古怪或低效的事情。替换列表元素是其中之一吗?有更简单(同样有效)的方法吗?

您可以使用
列表编写。折叠

let replace f sub xs = 
  let processItem (found,list) x =
    if found then (true,x::list) 
    elif f x then (true,(sub x)::list) 
    else (false,x::list)
  let (found, list) = xs |> List.fold processItem (false,[])
  if found then Some(List.rev list)
  else None
它稍微简单一些,并且具有类似的性能(列表元素上的单个循环)

更新

let replace pf sf xs =
  let find = ref false
  let rec aux = function
    | [] -> []
    | x::xs -> if pf x then find := true;(sf x) :: xs else x :: (aux xs)
  let xs = aux xs
  if !find then Some xs else None
(*
> let xs = [0..9];;
val xs : int list = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9]
> let subf = fun _ -> -1;;
val subf : 'a -> int

> replace ((=) 5) subf xs;;
val it : int list option = Some [0; 1; 2; 3; 4; -1; 6; 7; 8; 9]
> replace ((<) 5) subf xs;;
val it : int list option = Some [0; 1; 2; 3; 4; 5; -1; 7; 8; 9]
> replace ((=) 50) subf xs;;
val it : int list option = None
*)
让我们替换pf sf xs=
让find=ref为false
设rec aux=函数
| [] -> []
|x::xs->if pf x则find:=true;(sf x)::xs其他x::(辅助xs)
设xs=aux-xs
如果!然后查找一些xs,其他则没有
(*
>设xs=[0..9];;
val xs:int list=[0;1;2;3;4;5;6;7;8;9]
>让subf=fun->-1;;
val subf:'a->int
>替换((=)5)子项xs;;
val it:int list选项=一些[0;1;2;3;4;-1;6;7;8;9]
>替换((替换(=)50)子项xs;;
val it:int list选项=无
*)
如果您的应用程序可以接受复杂性,那么您的代码就是完美的。为了获得更好的复杂性,您需要解决线性搜索的需要,例如对元素施加顺序和使用二进制搜索树

不涉及搜索的一个相关问题是用已知索引替换列表元素:

val replaceAt : int -> 'a -> 'a list -> 'a list
对于这个问题,存在比标准列表更好的持久数据结构。在文献中搜索纯函数随机访问列表


奇怪的是,没有ML家族语言(OCaml、F#、SML)在标准列表库中定义
replace
replaceAt
。这可能是为了鼓励用户重新设计代码以避免
O(N)
这些操作的复杂性。

您不是在改变列表,而是在构建替换的结果。
O(N)
复杂性是否适合您的应用程序?如果是,您的代码是完美的;如果不是,您有两个选择:使用可变的DS,例如带有
O(1)
update但
O(N)的数组
clone;或者在文献中搜索纯功能随机访问列表(如冈崎)。@toyvo:我认为很明显我没有对列表进行变异(从技术意义上讲),因为这是不可能的。重建是唯一的选择。问题是,这个操作是否表明使用了错误的DS?搜索本身是O(N)(我不需要改进这一点)因此使用数组不会改变渐进复杂性(尽管它会大大提高实际成本)。@Daniel很抱歉用了这个词。是的,我没有密切注意,如果你在进行线性搜索,那么数组和RA列表都不会有任何帮助。那么列表就是正确的(简单)你能为你的元素排序吗?这将放入
log(N)
在表上搜索,比如说,在地图上搜索日志更新。也许我太担心了。缺少内置函数让我觉得我可能错过了一些明显的东西。@Daniel,奇怪的是SML和OCaml标准库都没有它:而且-我想这只是因为它是
O(N)
.OCaml支持assoc列表-也支持线性搜索。但它没有替换,我想通过assoc列表,您可以通过
(:)实现相同的效果
。是的,我所做的本质上是一个映射,但我避开了
列表。映射
,因为它需要可变性来跟踪列表是否发生了变化。虽然要短得多。+1此代码做了一些不同的事情:它替换与谓词
pf
匹配的所有元素,而问题中的代码只替换第一次出现的元素(如果!c=0&&(pfx).
很容易修复)@丹尼尔-嗯,我认为基本上是一样的。@MiMo-谢谢你指出。我误解了丹尼尔替换的行为。但是,正如已经显示的那样,更改似乎很容易。@BLUEPIXY:就我而言,差异并不重要,因为始终会有0或1个匹配元素。这里是
List.rev
,对吗这是一个额外的遍历吗?我想你是对的-这是一个额外的遍历-但自从我使用F#以来已经有一段时间了。。。
val replaceAt : int -> 'a -> 'a list -> 'a list