Haskell 两个列表中有多少元素是相同的,并且有重复的元素
我试图找出两个列表中相同的元素数量两个列表中有重复的元素 我想要的是:Haskell 两个列表中有多少元素是相同的,并且有重复的元素,haskell,Haskell,我试图找出两个列表中相同的元素数量两个列表中有重复的元素 我想要的是: -- (because there are two 's' in both lists ) duplicateEle "sssf" "ssah" = 2 -- (because there are two 'a' and one 's' in both lists, intotal 3 common elements) duplicateEle "aass" &q
-- (because there are two 's' in both lists )
duplicateEle "sssf" "ssah" = 2
-- (because there are two 'a' and one 's' in both lists, intotal 3 common elements)
duplicateEle "aass" "aaas" = 3
-- (because there are two 'a' and two 's' in both lists, intotal 4 common elements)
duplicateEle "ssaa" "ssaa" = 4
我的策略是检查列表1中的每个元素,看看它是否是列表2中的元素
- 如果列表1的每个元素都是列表2的元素
- 如果为true,计数1并删除第二个列表中的相应元素(Data.List)
d
首先,我检查列表1中的第一个元素d
是否是列表2中的元素,结果为True,因此我只删除了列表2中的一个d,count+1,现在count为1
然后我检查列表1中的第二个元素是d
是否是列表2中的元素,结果也是真的,因此,我在列表2中删除了一个d,count+1,现在count是2
因为列表2中没有剩余的d
,所以计数将保持在2
我的代码是:(错)
如果您只想在两个包含重复项的列表之间查找公共元素的数量,只需执行以下操作:
f x y = length $ nub $ intersect x y
intersect
将找到公共元素(重复*),而nub
将从该列表中获得不同的值
注意:intersect
将只包括第一个参数的重复,即intersect“ss”s
将返回“ss”,但intersect“s”ss
将只返回“s”
编辑:根据澄清,我们可以使用foldl
获得预期结果,如下所示:
dup x y = fst $ foldl (\acc z -> if z `elem` (snd acc) then ((1 + fst acc), delete z (snd acc)) else acc) (0,y) x
这适用于问题中概述的策略-如果在第二个列表的当前值中找到元素,则增加计数并修改第二个列表,否则什么也不做。如果您只想在两个列表之间找到具有重复项的公共元素数,您可以简单地执行以下操作:
f x y = length $ nub $ intersect x y
intersect
将找到公共元素(重复*),而nub
将从该列表中获得不同的值
注意:intersect
将只包括第一个参数的重复,即intersect“ss”s
将返回“ss”,但intersect“s”ss
将只返回“s”
编辑:根据澄清,我们可以使用foldl
获得预期结果,如下所示:
dup x y = fst $ foldl (\acc z -> if z `elem` (snd acc) then ((1 + fst acc), delete z (snd acc)) else acc) (0,y) x
这适用于问题中概述的策略-如果在第二个列表的当前值中找到元素,则增加计数并修改第二个列表,否则什么都不做。我相信,这就是您打算写的内容
import Data.List
duplicateEleCount :: [Char] -> [Char] -> Int
duplicateEleCount (x:xs) ys =
let (count, ys') = if x `elem` ys then (1, delete x ys) else (0, ys)
in count + duplicateEleCount xs ys'
duplicateEleCount [] _ = 0
你不能像以前那样使用do
。请记住,Haskell中的所有变量都是不可变的,因此delete
不会更改原始列表,它会返回一个新的列表,我们必须将其传递给递归调用
关于性能的一点说明:这个函数是O(n*m)
,因为我们必须为第一个列表中的每个元素遍历整个第二个列表。我们可以先对列表进行排序,然后从merge sort执行类似于合并操作的操作,将其降到O(n*log(n)+m*log(m))
另一方面,由于haskell的懒惰,我们可以像这样将函数拆分为一个函数,而不会损失任何性能并获得灵活性:
import Data.List
duplicateElems :: [Char] -> [Char] -> [Char]
duplicateElems (x:xs) ys =
if x `elem` ys
then x : duplicateElems xs (delete x ys)
else duplicateElems xs ys
duplicateElems [] _ = []
duplicateEleCount xs ys = length $ duplicateElems xs ys
我相信,这就是你打算写的
import Data.List
duplicateEleCount :: [Char] -> [Char] -> Int
duplicateEleCount (x:xs) ys =
let (count, ys') = if x `elem` ys then (1, delete x ys) else (0, ys)
in count + duplicateEleCount xs ys'
duplicateEleCount [] _ = 0
你不能像以前那样使用do
。请记住,Haskell中的所有变量都是不可变的,因此delete
不会更改原始列表,它会返回一个新的列表,我们必须将其传递给递归调用
关于性能的一点说明:这个函数是O(n*m)
,因为我们必须为第一个列表中的每个元素遍历整个第二个列表。我们可以先对列表进行排序,然后从merge sort执行类似于合并操作的操作,将其降到O(n*log(n)+m*log(m))
另一方面,由于haskell的懒惰,我们可以像这样将函数拆分为一个函数,而不会损失任何性能并获得灵活性:
import Data.List
duplicateElems :: [Char] -> [Char] -> [Char]
duplicateElems (x:xs) ys =
if x `elem` ys
then x : duplicateElems xs (delete x ys)
else duplicateElems xs ys
duplicateElems [] _ = []
duplicateEleCount xs ys = length $ duplicateElems xs ys
你写的不是那么草率。由于是字符串,我们可以对它们进行排序,然后分组:
import Data.List
-- group :: Eq a => [a] -> [[a]] -- Defined in `Data.List'
dupreps :: String -> String -> Int
dupreps a b = r
where
x = group $ sort a
y = group $ sort b
现在我们已经将它们进行了排序和分组,我们可以以一种明显的方式沿着这两个列表前进
r = merge'n'count x y 0
merge'n'count _ [] cnt = cnt
merge'n'count [] _ cnt = cnt
merge'n'count (g:gs) (f:fs) cnt
| head g == head f
= merge'n'count gs fs (cnt + min (length g) (length f))
| head g < head f
= merge'n'count gs (f:fs) cnt
| head g > head f
= merge'n'count (g:gs) fs cnt
merge'n'count
中的组g
和f
在构造上总是非空的,因此使用head
是可以的。你写的不是那么简单。由于是字符串,我们可以对它们进行排序,然后分组:
import Data.List
-- group :: Eq a => [a] -> [[a]] -- Defined in `Data.List'
dupreps :: String -> String -> Int
dupreps a b = r
where
x = group $ sort a
y = group $ sort b
现在我们已经将它们进行了排序和分组,我们可以以一种明显的方式沿着这两个列表前进
r = merge'n'count x y 0
merge'n'count _ [] cnt = cnt
merge'n'count [] _ cnt = cnt
merge'n'count (g:gs) (f:fs) cnt
| head g == head f
= merge'n'count gs fs (cnt + min (length g) (length f))
| head g < head f
= merge'n'count gs (f:fs) cnt
| head g > head f
= merge'n'count (g:gs) fs cnt
merge'n'count
中的组g
和f
在构造上总是非空的,因此使用head
是可以的。谢谢shree.pat18,您的解决方案太棒了。您的策略通常是可以的,但是使用do
在语法上是不正确的。此外,delete函数只删除列表中的第一个实例,因此如果在两个列表中重复相同的字符,最终仍然会重复计数是的,我实现了do
部分,因为在“if x then y else z”中y和z的类型应该相同。但是如果我想要两个运算,我怎么做呢,还有其他语句吗?关于列表
部分,由于我删除了第二个列表中的元素,因此不需要重复计算,因为元素将加倍计数已删除。我不确定您提到的“重复计算”是否正确。delete'a'“abca”
返回“bca”而不是“bc”,因此,如果您的第一个列表是“aab”,即使在为第一个实例“a”调用delete之后,第二个列表中还有另一个“a”,它将与第一个字符串中的第二个“a”相匹配。Prelude Data.list>length$nub$intersect“aaaa”“ssaa”
Hi shree,当输入为aaaa时,我发现了一个bug