这对我来说非常棘手。
鉴于列表非常长,
[[100,11,1,0,40,1],[100,12,3,1,22,23],[101,11,1,0,45,1],[101,12 ,3,1,28,30],[102,11,1,0,50,1],[102,12,3,1,50,50],[103,11,1,0,50,1 ],[103,12,3,1,50,50],[104,11,1,0,50,25],[104,12,3,1,50,50],[105,11,1 ,0,50,49],[105,12,3,0,30,30],[106,11,1,0,50,49],[106,12,3,0,25,26] [107,11,1,1,33,20],[107,12,3,0,25,26],[108,11,1,1,2,1],[108,12,3,1 ,20,24],[109,11,1,1,2,1],[109,12,3,1,28,31],[110,11,1,0,40,1],[110 ,12,3,1,22,23] ..]
现在igore每个列表的第一个数字,如果两个列表尽管第一个数字相同,例如
[101,11,1,0,50,1]
alike
[102,11,1,0,50,1]
我们保留后一个列表,直到整个列表全部被检查。理想情况下,结果应该是:
[[102,11,1,0,50,1],[103,12,3,1,50,50] ..]
我的想法是使用map取出第一个数字,使用nub和\\来摆脱所有重复的结果,使其成为像
[[11,1,0,50,1],[12,3,1,50,50],[12,3,1,50,50],[11,1,0,50,49 ],[12,3,0,25,26],[11,1,1,2,1],[11,1,0,40,1],[12,3,1,22,23] [11,1,0,45,1],[12,3,1,28,30] ..]
并使用Set.isSubsetOf过滤原始列表。
然而,这个想法太复杂,难以实施。由于我是Haskell的初学者,有没有更好的方法对此进行排序?或者我可以使用递归函数(尽管仍然需要努力)?
答案 0 :(得分:4)
根据您的描述,我认为您希望获得最后列表的列表,以获得每个独特的尾部。你可以这样做:
lastUniqueByTail :: Eq a => [[a]] -> [[a]]
lastUniqueByTail = reverse . nubBy ((==) `on` tail) . reverse
注意 这仅适用于非空列表的有限列表
您可以在on
模块中找到Data.Function
,然后在nubBy
中找到Data.List
。
所以这里是每个部分的解释,我们将从内到外工作:
((==) `on` tail)
此函数执行两个列表之间的比较,如果它们的尾部相等则确定它们是相等的(即它执行忽略第一个元素的相等性检查)。
on
功能正是这里的大部分魔力。它具有以下类型签名:
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
它基本上定义为(f `on` g) x y = f (g x) (g y)
,因此替换我们提供的函数,我们得到((==) `on` tail) x y = (tail x) == (tail y)
。
然后,nubBy
就像nub
,除了你可以提供一个比较器来测试相等性。我们给它上面定义的函数,以便丢弃具有相同尾部的元素。
nub
一样,nubBy
会在找到的每个等价类中保留第一个元素。 (即如果它在列表中找到两个相等的元素,它总是选择第一个)。我们想要最后这样的元素,这就是我们必须首先反转的原因(这样,最后一个相等的元素就成了第一个,所以保留了。)答案 1 :(得分:1)
如果您需要通过合并具有相同尾部的所有项目来压缩列表,请尝试使用此代码。
compactList:: [[Int]] -> [[Int]]
compactList list = reverse $ compactList' list []
compactList':: [[Int]] -> [[Int]] -> [[Int]]
compactList' [] res = res
compactList' (l:ls) res
| inList l res
= compactList' ls res
| otherwise
= compactList' ls (l:res)
inList :: [Int] -> [[Int]] -> Bool
inList [] _ = False
inList _ [] = False
inList val@(x:xs) ((x':xs'):ls)
| xs == xs'
= True
| otherwise
= inList val ls
如果我们需要"保留后者列表" (我之前错过了),然后只需更改reverse
compactList list = reverse $ compactList' list []
答案 2 :(得分:0)
你可以找到2个向量之间的欧几里德距离。例如,如果你有两个列表[a0,a1,...,an]和[b0,b1,...,bn],那么它们之间的欧几里德距离的平方将是
sum [ (a - b) ^ 2 | (a, b) <- zip as bs ]
这可以让您了解关闭一个列表与另一个列表的关系。理想情况下你应该采用平方根,但对于你正在做的事情,我不知道是否有必要。
编辑:
抱歉,我误解了你的问题。根据您的定义,alike
定义如下:
alike as bs = (tail as) == (tail bs)
如果是这种情况,那么类似下面的内容应该可以解决问题:
xAll [] = []
xAll xa@(x:xaa) = a : xAll b
where
a = last $ filter (alike x) xa
b = filter (\m -> not (alike x m)) xa
但不确定这是否是你要找的......