Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.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_Haskell - Fatal编程技术网

List 如果元素存在,则删除该元素,但将其添加到不存在的元素中的函数

List 如果元素存在,则删除该元素,但将其添加到不存在的元素中的函数,list,haskell,List,Haskell,我正在寻找一种更简洁的方法来编写一个函数,如果列表中不包含元素,就向列表中添加元素。或者如果列表中确实包含它,则删除它,我现在使用的是if子句,函数正在工作 但我正试图找到一个更像哈斯凯尔的方法来纠正这一点 这是我的代码: removeElemOrAdd :: Eq a => a -> [a] -> [a] removeElemOrAdd elem list = if (List.elem elem list) then

我正在寻找一种更简洁的方法来编写一个函数,如果列表中不包含元素,就向列表中添加元素。或者如果列表中确实包含它,则删除它,我现在使用的是
if
子句,函数正在工作

但我正试图找到一个更像哈斯凯尔的方法来纠正这一点

这是我的代码:

removeElemOrAdd :: Eq a => a -> [a] -> [a]
removeElemOrAdd elem list = if (List.elem elem list)
                            then (filter(\x -> x /= elem) list)
                            else (elem:list)

注意:您的问题中有一点模棱两可,即当原始列表中已多次出现
x
时,该怎么办。我假设这不会发生,如果发生,只删除第一个事件。这意味着
删除lemoradd 2[4,2,5,2,7]
将导致
[4,5,2,7]
。此外,还未指定应在何处添加项目。因为它有一些优点,所以我选择在列表末尾这样做

不使用任何库方法的实现如下所示:

removeElemOrAdd :: Eq a => a -> [a] -> [a]
removeElemOrAdd x (y:ys) | x == y = ys
                         | otherwise = y : removeElemOrAdd x ys
removeElemOrAdd x _ = [x]
或更简短的版本:

removeElemOrAdd :: Eq a => a -> [a] -> [a]
removeElemOrAdd x = reoa
    where reoa (y:ys) | x == y = ys
                      | otherwise = y : reoa ys
          reoa _ = [x]
或同等实施(见下文讨论):

该函数的工作原理如下:如果我们讨论的列表中至少有一个项
(y:ys)
,我们将
x
y
进行比较,如果它们相等,我们返回
ys
:在这种情况下,我们删除了元素,就完成了

现在如果两者不相等,我们返回一个列表结构
(:)
,头部带有
y
,因为我们需要保留
y
,在尾部,我们将使用
x
ys
执行递归调用
removeElemOrAdd
。事实上:可能在尾部的某个地方有一个
x
要删除,而且如果没有,我们仍然需要将
x
添加到列表中

该子句将在列表中递归循环。从它找到
y
的那一刻起,
x==y
它将删除该
y
。但是,有可能我们到达了列表的末尾,仍然没有找到元素。在这种情况下,我们称之为最终条款。在这里,我们知道列表是空的(我们可以编写
removeElemOrAdd x[]
),但是为了使函数定义在语法上完整,我选择使用下划线。只有在列表中找不到
x
时,我们才能达到此状态,因此我们通过返回
[x]
将其添加到列表的尾部

与使用
if-then-else
相比,这种方法的一个优点是可以一次完成所有任务(检查、删除和添加),从而提高效率


另一个优点是,它可以在“无限”列表上运行(比如素数列表)。列表是惰性计算的,因此如果要获取前三项,此函数将仅检查前三项的相等性。

我将使用折叠删除所有副本:

removeOrAdd x xs = foldr go (bool [x] []) xs False where
  go y r found
    | y == x = r True
    | otherwise = y : r found
要仅删除一个,似乎需要一个准形态:

removeOrAdd x = para go [x] where
  go y ys r
    | y == x = ys
    | otherwise = y : r

我喜欢其他方法,但不喜欢它们的行为与规范不同。因此,这里有一种方法:

  • 与原件一样,删除所有副本(如果有),然后
  • 与原始值一样,如果需要,在开始处插入新值,但
  • 与原始版本不同,它使用了一种基于(和后续开发)思想的巧妙技巧,只通过一次数据
  • 基本思想是,我们将有一个单一的值来跟踪到目前为止是否所有的值都是不匹配的,以及结果过滤列表。
    injectNE
    操作将对列表中的单个元素执行此操作,然后我们将使用
    foldMap
    从一个元素扩展到整个输入列表

    import Data.Monoid
    
    injectNE :: Eq a => a -> a -> (All, [a])
    injectNE old new = (All ne, [new | ne]) where
        ne = old /= new
    
    removeElemOrAdd :: Eq a => a -> [a] -> [a]
    removeElemOrAdd x xs = case foldMap (injectNE x) xs of
        (All nex, noxs) -> [x | nex] ++ noxs
    
    在最后一个模式中,您应该将
    nex
    解读为“没有元素等于
    x
    ”,将
    noxs
    解读为“没有任何
    x
    副本的列表”(明白了吗?“没有
    x
    s”?ba dum tsh)

    不过,有点遗憾的是,规范是按原样编写的:特别是,漂亮折叠的卖点之一是,它产生的一次性折叠对垃圾收集器更友好。但是规范使这变得非常困难,因为在决定结果列表的第一个元素应该是什么之前,我们必须遍历整个输入列表。我们可以通过放宽上述第(2)点(但保留第(1)点和第(3)点),显著提高对垃圾收集器的友好性;此外,区别仅仅是将参数交换为
    (++)
    ,这在您的修订历史记录中是一个很好的语义差异:

    -- <snipped identical code>
    removeElemOrAdd x xs = case ... of
        ... -> noxs ++ [x | nex]
    
    ——
    removeElemOrAdd x xs=案例。。。属于
    ... -> noxs++[x|nex]
    
    您正在寻找哪种“清洁剂”?关于简洁性,您的解决方案看起来不错。关于性能,您可以扫描列表一次以查找、删除和添加,但时间会更长。(顺便说一句,对称性被设计破坏了:你删除了所有匹配的元素,但只添加了一个。)一般来说,这对我来说很好——我猜你可以使用一个防护而不是if/then/else,但它会以相同的方式(递归地)运行,这就是“haskellish”@9000对这里的对称性提出了很高的要求though@CommuSoft:很难说无限列表中是否缺少一个项目,所以我认为无限序列的定义排除了它。从无限列表中删除一个项目当然是可能的,但你必须知道它是用来删除的,这在某种程度上违背了目的。@9000:关键是你可以将决定推迟到列表的末尾(对于无限列表来说,这是永远不会发生的)然后将该项添加为最后一个元素:因此每次必须枚举时,都要进行相等性检查。从找到这样的元素的那一刻起,您就不再关心向尾部添加元素了。关键是您事先不知道谁将调用您的函数,以及调用什么。@CommuSoft,即使添加了
    -- <snipped identical code>
    removeElemOrAdd x xs = case ... of
        ... -> noxs ++ [x | nex]