72 lines
2.4 KiB
Haskell
72 lines
2.4 KiB
Haskell
{-# LANGUAGE TupleSections #-}
|
|
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
|
|
|
|
module Multiset where
|
|
|
|
import Control.Monad
|
|
import qualified Data.IntSet as IS
|
|
import qualified Data.Map.Strict as M
|
|
import qualified IntMapHelp as IM
|
|
|
|
-- naive solution
|
|
powlistUpToN' :: Int -> [a] -> [[a]]
|
|
powlistUpToN' _ [] = [[]]
|
|
powlistUpToN' n (x : xs)
|
|
| n <= 0 = [[]]
|
|
| otherwise = ((x :) <$> powlistUpToN' (n -1) xs) ++ powlistUpToN' n xs
|
|
|
|
-- adapted from
|
|
-- https://stackoverflow.com/questions/21265454/subsequences-of-length-n-from-list-performance/59932616#59932616
|
|
-- uses dynamic programming: the important part is the use of "next" twice
|
|
-- there is a (probably) faster SO answer that produces power lists of size
|
|
-- exactly N, but that answer is harder to adapt
|
|
powlistUpToN :: Int -> [a] -> [[a]]
|
|
powlistUpToN n xs = concat $ drop (length xs - n) (subseqsBySize xs)
|
|
where
|
|
subseqsBySize [] = [[[]]]
|
|
subseqsBySize (y : ys) =
|
|
let next = subseqsBySize ys
|
|
in zipWith (++) ([] : next) (map (map (y :)) next ++ [[]])
|
|
|
|
powlistUpToN'' :: Int -> [a] -> [[a]]
|
|
powlistUpToN'' n xs =
|
|
let l = length xs
|
|
in -- in if n > l then [] else concat $ drop (l-n) (subseqsBySize xs)
|
|
if n > l
|
|
then concat $ subseqsBySize xs
|
|
else concat $ drop (l - n) (subseqsBySize xs)
|
|
where
|
|
subseqsBySize [] = [[[]]]
|
|
subseqsBySize (y : ys) =
|
|
let next = subseqsBySize ys
|
|
in zipWith (++) ([] : next) (map (map (y :)) next ++ [[]])
|
|
|
|
-- this is the code producing all exactly n length sublists
|
|
-- it is the reason for the incomplete-uni-patterns warning suppression
|
|
combinationsOf :: Int -> [a] -> [[a]]
|
|
combinationsOf 1 as = map pure as
|
|
combinationsOf k' as@(_ : xs) = run (l -1) (k' -1) as $ combinationsOf (k' -1) xs
|
|
where
|
|
l = length as
|
|
run :: Int -> Int -> [a] -> [[a]] -> [[a]]
|
|
run n k ys cs
|
|
| n == k = map (ys ++) cs
|
|
| otherwise = map (q :) cs ++ run (n -1) k qs (drop dc cs)
|
|
where
|
|
(q : qs) = take (n - k + 1) ys
|
|
dc = product [(n - k + 1) .. (n -1)] `div` product [1 .. (k -1)]
|
|
combinationsOf _ [] = []
|
|
|
|
-- exponential, so don't use it on long lists
|
|
powlist :: [a] -> [[a]]
|
|
powlist = filterM (const [True, False])
|
|
|
|
toMultiset :: Ord a => [a] -> M.Map a Int
|
|
toMultiset = foldr (uncurry (M.insertWith (+)) . (,1)) M.empty
|
|
|
|
invertIntMap :: Ord a => IM.IntMap a -> M.Map a IS.IntSet
|
|
invertIntMap =
|
|
IM.foldrWithKey
|
|
(\k x -> M.insertWith IS.union x (IS.singleton k))
|
|
M.empty
|