Создать список списков из списка при изменении одного и всегда другого значения Haskell - PullRequest
0 голосов
/ 20 февраля 2019

У меня есть список из 9 целых чисел со значениями 1, -1, 0, например:

[-1, 0, 0, 1, -1, -1, 1, 1, 0] 

Я пытаюсь сделать так, чтобы из этого одного списка создавался список списков, в котором каждый изони содержат только одно изменение и все время разные.Для каждого -1 я хочу изменить его на 0.

Пример:

Из списка:

[-1,0,0,1,-1,-1,1,1,0], 

Я хочу получитьрезультат:

[ [ 0, 0, 0, 1, -1, -1, 1, 1, 0]
, [-1, 0, 0, 1,  0, -1, 1, 1, 0]
, [-1, 0, 0, 1, -1,  0, 1, 1, 0]
]

Таким образом, у каждого списка есть только одно измененное значение, и у каждого есть другое.Я понятия не имею, как даже начать.

Ответы [ 3 ]

0 голосов
/ 21 февраля 2019

Еще одна попытка:

zeros :: [Int] -> [Int] -> [[Int]]
zeros _ []     = []
zeros h (x:xs) = [h ++ newX:xs] ++ zeros nextH xs
    where newX = if x == (-1) then 0 else x
        nextH = h ++ [x]

switch xs = ((filter (/= xs)) . (zeros [])) xs

Использование:

main = print $ switch [-1, 0, 0, 1, -1, -1, 1, 1, 0]
0 голосов
/ 21 февраля 2019

Очевидно, что это очень специфическая проблема.Часто бывает полезно взглянуть на более широкую картину: какая более общая проблема это частный случай?Понятно, что здесь мы просматриваем список и можем увидеть элемент, который мы хотим заменить, ноль или более.Далее, мы хотим посмотреть, сколько способов можно сделать ограниченное количество таких замен.Итак, давайте реализуем общий случай, прежде чем думать о том, как специализироваться на нашей первоначальной задаче:

import Control.Applicative (Alternative, empty, (<|>))

replaceNTimes :: Alternative f => (a -> f a) -> Int -> [a] -> f [a]
replaceNTimes _ 0 xs = pure xs
replaceNTimes _ _ [] = empty
replaceNTimes f n (x:xs) = replaceHere <|> keepLooking
  where replaceHere = (:) <$> f x <*> replaceNTimes f (n - 1) xs
        keepLooking = (x:) <$> replaceNTimes f n xs

Если у нас есть «бюджет» из оставшихся нулевых замен, мы просто возвращаем оставшуюся часть списка.Если у нас остался бюджет, но список пуст, мы отменяем, потому что мы не смогли сделать ожидаемое количество замен.В противном случае, мы обращаемся к нашей функции подсказки замены, чтобы увидеть, какие замены являются законными в текущей позиции, и выбираем либо сделать одну из них и выполнить рекурсию с меньшим N, либо сделать таковую и рекурсировать с тем же N.

С этим инструментом в нашем распоряжении, исходная проблема проста: мы просто специализируем N на 1 (производим ровно одну замену) и предоставляем заменяющую функцию, которая предлагает только замену -1 на 0:

replaceSingleNegativeOneWithZero :: [Int] -> [[Int]]
replaceSingleNegativeOneWithZero = replaceNTimes go 1
  where go (-1) = [0]
        go _ = []

И проверьте, чтобы мы получили ожидаемый результат:

*Main> replaceSingleNegativeOneWithZero [-1,0,0,1,-1,-1,1,1,0]
[ [0,0,0,1,-1,-1,1,1,0]
, [-1,0,0,1,0,-1,1,1,0]
, [-1,0,0,1,-1,0,1,1,0]]
0 голосов
/ 20 февраля 2019

Первое, что вам всегда нужно, это выяснить сигнатуру типа вашей функции.В вашем случае вы хотите

lister :: [Int] -> [[Int]]

Затем, когда вы хотите перебрать список, но следите за индексами, которые вы изменили, простым способом было бы составить список вашего списка (трудно следовать, просто посмотрите на код), а затем застегните его с индексом.Затем для каждого списка вы переключаете элемент в этой позиции.Это ваш код

lister :: [Int] -> [[Int]]
lister ls = [switch i l | (i,l) <- zip [0..9] (repeat ls)]

Затем вам нужна функция переключения, чтобы переключить элемент в i-й позиции в соответствии с вашим правилом:

switch :: Int -> [Int] -> [Int]
switch 0 ls = ls
switch n ls = [if i == n && x == -1 then 0 else x | (i,x) <- zip [1..] ls]

Обратите внимание, что это возвращает 9 списков, одиндля каждого элемента в вашем исходном списке.Поэтому он содержит несколько дубликатов.Вы можете устранить их, используя nub из Data.List, остерегайтесь, потому что это O(n^2)

Это ваш полный код:

import Data.List

lister :: [Int] -> [[Int]]
lister ls = nub [switch i l | (i,l) <- zip [0..9] (repeat ls)]

switch :: Int -> [Int] -> [Int]
switch 0 ls = ls
switch n ls = [if i == n && x == -1 then 0 else x | (i,x) <- zip [1..] ls]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...