Самый простой способ добиться желаемого - создать все комбинации и отфильтровать те, которые имеют значение:
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
для хранения дополнительной информации, например, типа последнего символа (чтобы избежать +*
последовательностей).