根据字段子集的列表中的唯一元素

Unique elements from a list according to a subset of fields

给定一条像

这样的记录
data Foo = Foo { fooName :: Text, fooAge :: Int, fooCity :: Text }

有了这些元素的列表,在这个假设的 removeDupBy 函数的模型上,是否有一个函数可以仅删除字段子集上的重复项?

foos =
  [
    Foo "john" 32 "London",
    Foo "joe" 18 "New York",
    Foo "john" 22 "Paris",
    Foo "john" 32 "Madrid",
    Foo "joe" 17 "Los Angeles",
    Foo "joe" 18 "Berlin"
  ]

> removeDupBy (\(Foo f) -> (fooName, fooAge)) foos 
[
    Foo "john" 32 "London",
    Foo "joe" 18 "New York",
    Foo "john" 22 "Paris",
    Foo "joe" 17 "Los Angeles"
]

我可以实现我自己的,但更喜欢使用一个来自成熟库的库,它可能性能更高,并且对边缘情况更有弹性。我正在考虑使用 nub,但我不确定如何将实际的 Foo 元素映射到 nub 会过滤掉的元组 (fooName, fooAge)

您可以使用 nubBy:

Prelude Data.List> nubBy (\x y -> (fooName x, fooAge x) == (fooName y, fooAge y)) foos
[Foo {fooName = "john", fooAge = 32, fooCity = "London"},
 Foo {fooName = "joe", fooAge = 18, fooCity = "New York"},
 Foo {fooName = "john", fooAge = 22, fooCity = "Paris"},
 Foo {fooName = "joe", fooAge = 17, fooCity = "Los Angeles"}]

(输出格式化以增强可读性)

因为你只处理字符串和数字,你可以使用 Ord 实例来有效地删除重复项,甚至 Hashable,它允许几乎恒定时间的查找。

一些与您想要的签名完全匹配的函数是:

  1. nubOrdOn from the containers 包裹
Data.Containers.ListUtils> nubOrdOn (\f -> (fooName f, fooAge f)) foos
  1. hashNubOn from the witherable 包裹
Witherable> hashNubOn (\f -> (fooName f, fooAge f)) foos

您可以通过搜索 Hoogle for (a -> b) -> [a] -> [a]

找到其他选项

如果你需要做很多这样的操作,你可能更愿意直接使用MapHashMap