我想根据一般规格创建一系列可能的方程式:
test = ["12", "34=", "56=", "78"]
每个字符串(例如“ 12”)代表该位置的可能字符,在这种情况下为“ 1”或“ 2”。) 因此,来自测试的可能方程式为“ 13 = 7”或“ 1 = 68”。 我知道我给出的示例并不均衡,但这是因为我故意给出了一个简化的短字符串。 (我也知道我可以使用“序列”来搜索所有可能性,但我想变得更聪明,因此需要下面说明的另一种方法。)
我想要的是尝试依次固定每个等式,然后删除等式中的所有其他等式。所以我想要:
[["12","=","56","78"],["12","34","=","78”]]
我写了这个嵌套列表理解: (它需要:{-#LANGUAGE ParallelListComp#-})
fixEquals :: [String] -> [[String]]
fixEquals re
= [
[
if index == outerIndex then equals else remain
| equals <- map (filter (== '=')) re
| remain <- map (filter (/= '=')) re
| index <- [1..]
]
| outerIndex <- [1..length re]
]
这将产生:
[["","34","56","78"],["12","=","56","78"],["12","34","=","78"],["12","34","56","”]]
但是我想过滤掉其中任何带有空列表的东西。即在这种情况下,第一个和最后一个。
我可以做到:
countOfEmpty :: (Eq a) => [[a]] -> Int
countOfEmpty = length . filter (== [])
fixEqualsFiltered :: [String] -> [[String]]
fixEqualsFiltered re = filter (\x -> countOfEmpty x == 0) (fixEquals re)
以便“ fixEqualsFiltered测试”给出:
[["12","=","56","78"],["12","34","=","78”]]
这是我想要的,但看起来并不优雅。 我不禁想到还有另一种方法可以将其过滤掉。 毕竟,无论何时要在if语句中使用“等于”并且为空时,我们都要删除等于,因此构建列表似乎很浪费(例如[“”,“ 34”,“ 56”,“ 78” ],然后将其抛弃。)
任何想法都很感激。
答案 0 :(得分:3)
让
xs = [["","34","56","78"],["12","=","56","78"],["12","34","=","78"],["12","34","56",""]]
在
filter (not . any null) xs
会给予
[["12","=","56","78"],["12","34","=","78"]]
如果您想要列表理解,那就
[x | x <- xs, and [not $ null y | y <- x]]
答案 1 :(得分:3)
我不知道这是否比您的代码更干净,但是使用递归可能会更清晰,更有效:
fixEquals = init . f
f :: [String] -> [[String]]
f [] = [[]]
f (x:xs) | '=' `elem` x = ("=":removeEq xs) : map (removeEq [x] ++) (f xs)
| otherwise = map (x:) (f xs)
removeEq :: [String] -> [String]
removeEq = map (filter (/= '='))
它的工作方式是,如果当前字符串中有一个'='
,那么它将返回值分成两部分,即使不是递归调用也是如此。 init
是必需的,因为返回的最后一个元素在任何字符串中都不相等。
最后,我相信您可以找到一个更好的数据结构来完成所需的工作,而不是使用字符串列表
答案 2 :(得分:2)
我想我可能会这样做。首先,我已经写了很多次的入门文章,现在几乎已经被我的手指烫了:
zippers :: [a] -> [([a], a, [a])]
zippers = go [] where
go _ [] = []
go b (h:e) = (b,h,e):go (h:b) e
在ghci中运行一两次可能会比我能做的任何英语著作更清楚地说明其作用:
> zippers "abcd"
[("",'a',"bcd"),("a",'b',"cd"),("ba",'c',"d"),("cba",'d',"")]
换句话说,它提供了一种依次选择列表中每个元素的方式,给出了选择点之前和之后的“剩余”。有了该工具,这就是我们的计划:我们将不确定地选择一个String
作为我们的等号,再次检查我们是否首先有一个等号,然后从中清除等号。其他。所以:
fixEquals ss = do
(prefix, s, suffix) <- zippers ss
guard ('=' `elem` s)
return (reverse (deleteEquals prefix) ++ ["="] ++ deleteEquals suffix)
deleteEquals = map (filter ('='/=))
让我们尝试一下:
> fixEquals ["12", "34=", "56=", "78"]
[["12","=","56","78"],["12","34","=","78"]]
完美!但这只是实际生成方程式的垫脚石,对吗?事实证明,跳过这一中间步骤并不困难。让我们做到这一点:
equations ss = do
(prefixes, s, suffixes) <- zippers ss
guard ('=' `elem` s)
prefix <- mapM (filter ('='/=)) (reverse prefixes)
suffix <- mapM (filter ('='/=)) suffixes
return (prefix ++ "=" ++ suffix)
我们可以在ghci中尝试它:
> equations ["12", "34=", "56=", "78"]
["1=57","1=58","1=67","1=68","2=57","2=58","2=67","2=68","13=7","13=8","14=7","14=8","23=7","23=8","24=7","24=8"]
答案 3 :(得分:1)
实现所需的最简单的方法是创建所有组合并过滤具有含义的组合:
Prelude> test = ["12", "34=", "56=", "78"]
Prelude> sequence test
["1357","1358","1367","1368","13=7","13=8","1457","1458","1467","1468","14=7","14=8","1=57","1=58","1=67","1=68","1==7","1==8","2357","2358","2367","2368","23=7","23=8","2457","2458","2467","2468","24=7","24=8"
Prelude> filter ((1==).length.filter('='==)) $ sequence test
["13=7","13=8","14=7","14=8","1=57","1=58","1=67","1=68","23=7","23=8","24=7","24=8","2=57","2=58","2=67","2=68"]
您指出了一个缺点:假设我们有以下字符串列表:["=", "=", "0123456789", "0123456789"]
。我们将生成100个组合并将其全部删除。
您可以将组合视为一棵树。对于["12", "34"]
,您具有:
/ \
1 2
/ \ / \
3 4 3 4
您可以修剪树:当路径上有两个=
时,只需忽略子树。
让我们尝试去做。首先,一个简单的combinations
函数:
Prelude> :set +m
Prelude> let combinations :: [String] -> [String]
Prelude| combinations [] = [""]
Prelude| combinations (cs:ts) = [c:t | c<-cs, t<-combinations ts]
Prelude|
Prelude> combinations test
["1357","1358","1367","1368","13=7","13=8","1457","1458","1467","1468","14=7","14=8","1=57","1=58","1=67","1=68","1==7","1==8","2357","2358","2367","2368","23=7","23=8","2457","2458","2467","2468","24=7","24=8", ...]
第二,我们需要一个变量来存储遇到的=
个符号的当前数量:
=
符号,只需放下子树=
的情况下到达组合的结尾,请删除组合即:
Prelude> let combinations' :: [String] -> Int -> [String]
Prelude| combinations' [] n= if n==1 then [""] else []
Prelude| combinations' (cs:ts) n = [c:t | c<-cs, let p = n+(fromEnum $ c=='='), p <= 1, t<-combinations' ts p]
Prelude|
Prelude> combinations' test 0
["13=7","13=8","14=7","14=8","1=57","1=58","1=67","1=68","23=7","23=8","24=7","24=8","2=57","2=58","2=67","2=68"]
p
作为路径上新的=
符号:如果p>1
,则删除子树。n
为零,则路径中没有任何=
符号,请删除组合。您可以使用变量n
存储更多信息,例如最后一个字符的类型(避免使用+*
序列)。