在数学中,当我想重新排列长度为n的列表时,我将使用排列对列表进行操作。例如:
(1 2) * (x, y, z) = (y, x, z)
(1 n 2) * (v[1], v[2], ..., v[n]) = (v[n], v[1], ..., v[2])
perm * (v[1], v[2], ..., v[n]) = ( v[perm(1)], v[perm(2)], ..., v[perm(n)] )
我如何在Haskell中执行此操作?
答案 0 :(得分:2)
我会使用输入排列来构建从旧索引到新索引的映射。
import Prelude hiding ((*))
import qualified Data.Map as M
infixr 5 * -- right-associative so we can compose permutations conveniently
(*) :: [Int] -> [a] -> [a]
perm * xs = zipWith (\i _ -> xs !! M.findWithDefault i i ixMap) [0..] xs
where ixMap = M.fromList (zip perm (drop 1 perm ++ take 1 perm))
您可以在ghci提示符中看到它的运行情况(尽管在编程中它通常使用基于0而不是基于1的索引):
> [0,1] * "xyz"
"yxz"
> [0,4,1] * "abcde"
"eacdb"
这需要O(n ^ 2 log m),其中n是xs
的长度,m是perm
的长度。您可以通过从(!!)
切换到M.lookup
将索引编入xs
,将其减少到O(n log(nm))。