Потеря элементов в списке кортежей во время рекурсии и защита не подбираются при условии - PullRequest
1 голос
/ 06 августа 2020

У меня проблема с тем, что у меня есть база данных, состоящая из списка кортежей, относящихся к хранению песни, исполнителя и данных о продажах. Мне нужно перебрать список, используя songName и artistName, и если они находятся в базе данных, я должен увеличить значение продаж на единицу и вывести его вместе с другими кортежами в базе данных. Если songName и artistName отсутствуют в базе данных, я должен вывести кортежи в базе данных вместе с новым кортежем, содержащим введенные songName, artistName и первую продажу, например [("Heartbeat","Kelly Clarkson",7), ("Rise","The Shadows",15), <strong>("Hello", "Adele", 1)</strong>].

Мое решение проблемы находится ниже:

testData :: [Sales]
testData = [ ("No Lie", "Sean Paul feat. Dua Lipa",  100)
           , ("Yes Lie", "Sean Paul feat. Dua Lipa",  10)
           , ("Fear & Delight", "The Correspondents",  120) ]



recordSale :: [Sales] -> String -> String-> [Sales]

recordSale [dataSet] trackName artistName = [(trackName, artistName, 1)]
recordSale ((track, artist, qty): xs) trackName artistName 
     | track == trackName && artist == artistName = xs ++ [(track, artist, qty + 1)]
     | otherwise = recordSale xs trackName artistName
     | track /= trackName && artist /= artistName = xs ++ [(track, artist, 1)]

Я написал рекурсивную функцию с охраной, чтобы попытаться найти имя песни и имя исполнителя в наборе данных, однако у меня есть странный неожиданный результат.

При вводе данных у меня есть странный вывод. Если бы я ввел recordSale testData "Yes Lie" "Sean Paul feat. Dua Lipa", программа выдала бы [("Fear & Delight","The Correspondents",120),("Yes Lie","Sean Paul feat. Dua Lipa",11)]. Примите ожидаемую проблему с отсутствующим элементом, описанную в Проблеме 1.

Однако, если бы я ввел recordSale testData "Fear & Delight" "The Correspondents", я бы получил необычное поведение или получил бы [("Fear & Delight","The Correspondents",1)]. Учитывая, что эта песня находится в базе данных, я ожидал, что цифра продаж увеличится на 1.

Учитывая, что песня была только выведена, а не песня, прикрепленная к списку, я думаю, что это могло быть вызвано моим базовый случай recordSale [dataSet] trackName artistName = [(trackName, artistName, 1)], но я не уверен на 100% в этом

Как мне go вернуть песню, которой нет в списке с продажей 1, и остановить успешные запросы, возвращающие 1 для их продаж, когда они включены в базу данных?

РЕДАКТИРОВАТЬ:

Заменено recordSale [dataSet] trackName artistName = [] на recordSale [dataSet] trackName artistName = [(trackName, artistName, 1)], чтобы более точно отразить проблему, с которой я столкнулся с Проблемой 2.

РЕДАКТИРОВАТЬ 2: Отредактирована формулировка проблемы 2, чтобы она была более «читабельной».

РЕДАКТИРОВАТЬ 3: Сообщение сокращено до одного вопроса.

1 Ответ

1 голос
/ 07 августа 2020

Есть две проблемы с вашим кодом. Первый находится в охраннике

     | otherwise = recordSale xs trackName artistName
     | track /= trackName && artist /= artistName = xs ++ [(track, artist, 1)]

Что происходит, когда пара trackName и artistName не является точным совпадением, список усекается, потому что вы передаете только xs. Вторая строка, которая обрабатывает точное несоответствие, никогда не будет обнаружена, потому что шаблоны упорядочены, а otherwise является универсальным. (Реализация в любом случае неверна, потому что она добавляет новый элемент всякий раз, когда текущий элемент не совпадает)

Другая проблема в шаблоне

recordSale [dataSet] trackName artistName = [(trackName, artistName, 1)]

Это соответствует, когда в списке есть только один элемент, но что, если этот элемент соответствует? В настоящее время этот случай игнорируется, и счетчик просто установлен на 1.

Следовательно, я бы предложил следующее:

(я также заменил конкатенацию списков ++ построением списка : потому что это экономит часть набора и удаляет немного беспорядка)

type Sales = (String, String, Int)

testData :: [Sales]
testData = [ ("No Lie", "Sean Paul feat. Dua Lipa",  100)
           , ("Yes Lie", "Sean Paul feat. Dua Lipa",  10)
           , ("Fear & Delight", "The Correspondents",  120) ]

recordSale :: [Sales] -> String -> String-> [Sales]
recordSale [] trackName artistName = [(trackName, artistName, 1)]
recordSale ((track, artist, qty): xs) trackName artistName 
     | track == trackName && artist == artistName = (track, artist, qty + 1) : xs
     | otherwise = (track, artist, qty) : recordSale xs trackName artistName

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

Живой пример на Wandbox

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...