【发布时间】:2019-12-27 21:36:26
【问题描述】:
问题
如何实现一个运行长度编码模数n>=1?对于n=4,考虑到输入AAABBBBABCCCCBBBDAAA,我们想要输出[('D', 1), ('A', 3)]。请注意由于模运算而导致的长距离合并。见说明。
说明
BBBB 的第一次出现编码为(B, 4),其modulus 4 是(B, 0),从而抵消了自身。参见图表(忽略空格;它们仅用于说明目的):
AAABBBBABCCCCBBBDAAA
A3 B4 ABCCCCBBBDAAA
A3 B0 ABCCCCBBBDAAA
A3 ABCCCCBBBDAAA
A4 BCCCCBBBDAAA
A0 BCCCCBBBDAAA
BCCCCBBBDAAA
...
DA3
一个更简单的例子,当没有合并发生时,因为没有被modulus 4取消:输入AAABABBBC产生输出[('A',3),('B',1),('A',1),('B',3),('C',1)]。
要求
- Haskell 实现是首选,但也欢迎其他实现!
- 首选标准/通用库函数而不是第三方库。
- 更喜欢使用高阶函数的可读且简洁的程序。
- 优先考虑效率(不必要时不要遍历整个列表)
我的程序
我在 Haskell 中实现了这一点,但它看起来太冗长且难以阅读。关键思想是一次检查三个元组,如果我们既不能取消 我的输入就像上面截图中的 0 元组,也不能合并手头的三个元组中的一对元组,只能向前推进一个元组。 p>
import Data.List (group)
test = [('A', 1), ('A', 2), ('B', 2), ('B', 2), ('A', 1), ('B', 1), ('C', 1), ('C', 3), ('B', 3), ('D', 1), ('A', 3)] :: [(Char, Int)]
expected = [('D', 1), ('A', 3)] :: [(Char, Int)]
reduce' :: [(Char, Int)] -> [(Char, Int)]
reduce' [ ] = [] -- exit
reduce' ( (_,0):xs) = reduce' xs
reduce' (x1:(_,0):xs) = reduce' (x1:xs)
reduce' ( (x,n):[]) = (x,n):[] -- exit
reduce' ( (x1,n1):(x2,n2):[]) -- [previous,current,NONE]
| x1 == x2 = reduce' ((x1, d4 (n1+n2)):[])
| otherwise = (x1,n1):( -- advance
reduce' ((x2, d4 n2 ):[]))
reduce' ((x1,n1):(x2,n2):(x3,n3):xs) -- [previous,current,next]
| n3 == 0 = reduce' ((x1, d4 n1 ):(x2, d4 n2 ):xs)
| n2 == 0 = reduce' ((x1, d4 n1 ):(x3, d4 n3 ):xs)
| x2 == x3 = reduce' ((x1, d4 n1 ):(x2, d4 (n2+n3)):xs)
| x1 == x2 = reduce' ((x2, d4 (n1+n2)):(x3, d4 n3 ):xs)
| otherwise = (x1,n1):( -- advance
reduce' ((x2, d4 n2 ):(x3, d4 n3 ):xs)
)
-- Helpers
flatten :: [(Char, Int)] -> String
flatten nested = concat $ (\(x, n) -> replicate n x) <$> nested
nest :: String -> [(Char, Int)]
nest flat = zip (head <$> xg) (d4 .length <$> xg)
where xg = group flat
reduce = reduce' . nest
d4 = (`rem` 4)
想法
test 变量。我们可以继续做flatten 然后nest 直到它的结果没有改变,并且肯定看起来更简单。但感觉它是多次扫描整个列表,而我的 3 指针实现只扫描整个列表一次。也许我们可以在合并相同的连续项目时从左侧弹出一个元素并将其添加到新堆栈中?或者也许使用应用函子?例如。这可行,但不确定其效率/性能:reduce = (until =<< ((==) =<<)) (nest . flatten)。
【问题讨论】:
-
这里的问题是什么?您似乎是在邀请讨论,而不是提出问题。
-
我正在寻求比我所拥有的更好的实现,并分享我的一些想法,因为有些人可能会发现这样的上下文很有帮助。
-
我应该删除我的实现和想法,只留下问题吗?
-
FWIW 我认为这是一个合理的问题。人们总是问“我怎么做 x?”,而我们反过来问“你试过什么?”。这个问题询问如何做 x,并说“这是我尝试过的:我的实现显然很糟糕,我正在寻找一个好的实现。”
-
这真的和Zuma game的问题很相似。
标签: algorithm list haskell compression finite-group-theory