替换列表中的元组

时间:2017-02-13 14:26:31

标签: sml smlnj

所以我有一个元组列表如下:

<Compile Include="x" />

如何创建一个可以删除副本的函数,用第一个副本的值替换第一个匹配项?

即。上面的列表将成为:

val mylist = [(1,"h"),(3,"l"),(45,"j"),(3, "x")] : (int * string) list

如果我有清单:

val mylist = [(1,"h"),(3,"x"),(45,"j")] : (int * string) list

这将成为:

val mylist = [(1,"h"),(3,"l"),(45,"j"),(3, "x"), (3, "f")] : (int * string) list

编辑:我创建了此功能,删除重复项,但不替换值:

val mylist = [(1,"h"),(3,"f"),(45,"j")] : (int * string) list

1 个答案:

答案 0 :(得分:2)

您的描述与第二个示例并不完全相符。您说您想要使用第一个副本替换该值,但在第二个示例中,您将(3,"l")替换为 last 重复((3,"f")而非比(3,"x"))。两者都可以完成,尽管用最后一个副本替换要容易得多。

要替换最后一个副本,请通过更新明确的键值对列表来查看最终列表。编写一个执行此更新的函数,然后在列表中运行此更新函数,从空列表开始:

fun update (i,c) [] = [(i,c)]
|   update (i,c) ((j,d)::records) = 
        if i = j then
            (i,c)::records
        else
            (j,d) :: (update (i,c) records)

fun updateAll [] records = records
|   updateAll ((i,c)::pairs) records = updateAll pairs (update (i,c) records)

fun removeVarDuplicates pairs = updateAll pairs [];

此功能可用于您的两个示例。

为了完整性,这里有一种方法,它是最终保留的第一个重复值。为此,请添加一个布尔标志,该标志将告诉您该值是否已更新。第一次更新 - 设置标志。剥去最终结果中的旗帜:

fun update (i,c) [] = [(i,c,false)]
|   update (i,c) ((j,d,t)::triples) = 
        if i = j then
            if t then (j,d,t) :: triples else (j,c,true)::triples
        else
            (j,d,t) :: (update (i,c) triples)

fun updateAll [] triples = triples
|   updateAll ((i,c)::pairs) triples = updateAll pairs (update (i,c) triples)

fun removeVarDuplicates pairs = 
    let
        val triples = updateAll pairs []
    in
        map (fn (x,y,_) => (x,y)) triples
    end;

当针对你的第二个例子运行时:

- val mylist = [(1,"h"),(3,"l"),(45,"j"),(3, "x"), (3, "f")];
val mylist = [(1,"h"),(3,"l"),(45,"j"),(3,"x"),(3,"f")] : (int * string) list
- removeVarDuplicates mylist;
val it = [(1,"h"),(3,"x"),(45,"j")] : (int * string) list

保留第一个重复键"x"的第一个值,而不是第二个重复键的值。

对于任何涉及键和值的严肃工作,您应该考虑使用不同的数据结构,例如SML / NJ&#39; hash table。我上面给出的代码非常低效,最终结果是O(n)查找的数据结构。