如果第一个元组的第二个元素与第二个元组的第一个元素相同,我的家庭作业是将两个元组分组到一个列表中。然后,如果第一个元组是 (a, b)
第二个是 (b, c)
,元组 (a, c)
必须添加到结果列表中。
我编写了第一个函数,它接收带有一个元组的元素和带有多个元组的第二个列表,并将每个列表进行比较。
这个正确地工作:
c1 = ("a","x")
d1 = [ ("x","b"), ("z","c"), ("x","b"), ("z","c")
, ("x","b"), ("z","c"), ("x","b"), ("z","c") ]
getByOne c1 a1 = filter (/=[])
[ if (fst (last(take n a1))) == (snd c1)
then [((fst c1), (snd (last(take n a1))))]
else [] | n <- [1..(length a1) ] ]
输出:
[ [("a","b")], [("a","b")], [("a","b")], [("a","b")] ]
但问题是我不能把 if then 和 else 语句扔进简单的元组,所以我创建了一个新列表。在这个“解决方法”的最后,我得到了 list in list in list 等等。此外,如果输出列表更大,列表中的列表就会更多。
有什么方法可以只传递元组或空元组,或者我应该以某种方式对论文列表进行分组?
最佳答案
您可以使用扁平化结果
concat :: [[a]] -> [a]
那么你甚至不需要
filter (/=[])
- 顺便说一下,条件 (/= [])
写得更地道not . null
, 自 null
测试不会施加 Eq
对其论点的约束(您在这里已经有了一个,所以这只是一个习语问题)。此外,
last (take n a1)
就是 n
a1
的第 - 个元素如果 1 <= n <= length a1
.由于您施加了该限制,因此可以更简洁地表示为 a1 !! (n-1)
然后你在结构上
getByOne c1 a1 = concat $ [something c1 (a1 !! i) | i <- [0 .. length a1 - 1]]
(我已将索引移至索引
i
),这更清晰,更有效地表示为getByOne c1 a1 = concat $ map (something c1) a1
如果您更喜欢列表解析而不是
map
,你也可以写成getByOne c1 a1 = concat [something c1 x | x <- a1]
在你的情况下,使用 alist-comprehension 生成器中的模式匹配能力,给了我们
getByOne (f,s) a1 = concat [ if a == s then [(f,b)] else [] | (a,b) <- a1]
这是更短,更易读。而不是使用
if condition then [element] else []
和 concat
,更好的是在列表理解中使用条件,getByOne (f,s) list = [(f,b) | (a,b) <- list, a == s]
这是简短而清晰的。
关于list - Haskell - 如果否则返回干净的元组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13217546/