From 69c53a794918d812fe2af7cdc93b14ab96e39824 Mon Sep 17 00:00:00 2001 From: robonen Date: Tue, 2 May 2023 21:10:55 +0700 Subject: [PATCH] Initial commit --- .gitignore | 3 +++ repl.sh | 18 +++++++++++++ run.sh | 25 +++++++++++++++++++ src/1a/1a.hs | 17 +++++++++++++ src/1b/1b.hs | 18 +++++++++++++ src/2a/2a.hs | 12 +++++++++ src/2b/2b.hs | 12 +++++++++ src/3/3.hs | 62 +++++++++++++++++++++++++++++++++++++++++++++ src/4/4.hs | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/4/4.old.hs | 47 ++++++++++++++++++++++++++++++++++ src/4/data.txt | 11 ++++++++ 11 files changed, 293 insertions(+) create mode 100644 .gitignore create mode 100755 repl.sh create mode 100755 run.sh create mode 100644 src/1a/1a.hs create mode 100644 src/1b/1b.hs create mode 100644 src/2a/2a.hs create mode 100644 src/2b/2b.hs create mode 100644 src/3/3.hs create mode 100644 src/4/4.hs create mode 100644 src/4/4.old.hs create mode 100644 src/4/data.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c69aa7a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +.vscode +build/* diff --git a/repl.sh b/repl.sh new file mode 100755 index 0000000..47a8536 --- /dev/null +++ b/repl.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env sh + +PROG_NAME=$1 + +if [ -z "$PROG_NAME" ]; then + echo "Usage: run.sh " + exit 1 +fi + +# Source and build paths +SRC_PATH=src/$PROG_NAME/$PROG_NAME.hs + +if [ ! -f $SRC_PATH ]; then + echo "File $SRC_PATH does not exist" + exit 1 +fi + +ghci $SRC_PATH \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..eb43472 --- /dev/null +++ b/run.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env sh + +PROG_NAME=$1 + +if [ -z "$PROG_NAME" ]; then + echo "Usage: run.sh " + exit 1 +fi + +# Source and build paths +SRC_PATH=src/$PROG_NAME/$PROG_NAME.hs +BUILD_PATH=build/$PROG_NAME + +# Build trash paths +OBJ_PATH=src/$PROG_NAME/$PROG_NAME.o +HI_PATH=src/$PROG_NAME/$PROG_NAME.hi + +if [ ! -f $SRC_PATH ]; then + echo "File $SRC_PATH does not exist" + exit 1 +fi + +ghc -o $BUILD_PATH $SRC_PATH \ + && rm $OBJ_PATH $HI_PATH \ + && ./$BUILD_PATH \ No newline at end of file diff --git a/src/1a/1a.hs b/src/1a/1a.hs new file mode 100644 index 0000000..bb63f1e --- /dev/null +++ b/src/1a/1a.hs @@ -0,0 +1,17 @@ +-- На вход функции подается два числовых списка [a1, a2, …,an] +-- и [b1, b2, …, bn]. Функция должна формировать новый +-- список [min(a1,b1), min(a2,b2), …, min(an,bn)]. + +mmin :: Ord a => a -> a -> a +mmin x y = if x < y then x else y + +minList :: [Int] -> [Int] -> [Int] +minList [] _ = [] +minList _ [] = [] +minList (x:xs) (y:ys) = mmin x y : minList xs ys + +main :: IO () +main = do + let a = [0, 5, 10, 3] + let b = [5, 1, 3] + print $ minList a b \ No newline at end of file diff --git a/src/1b/1b.hs b/src/1b/1b.hs new file mode 100644 index 0000000..000858e --- /dev/null +++ b/src/1b/1b.hs @@ -0,0 +1,18 @@ +-- Напишите функцию, зависящую от двух аргументов x и y, +-- удаляющую все вхождения x в список y. Х может быть атомом или списком. + +removeElem :: Eq a => a -> [a] -> [a] +removeElem _ [] = [] +removeElem y (x:xs) + | x == y = removeElem y xs + | otherwise = x : removeElem y xs + +removeAll :: Eq a => [a] -> [a] -> [a] +removeAll [] x = x +removeAll (y:ys) x = removeAll ys (removeElem y x) + +main :: IO () +main = do + let x = [1, 2, 3, 4, 5, 6, 7] + print $ removeAll [3] x + print $ removeAll [2, 5] x \ No newline at end of file diff --git a/src/2a/2a.hs b/src/2a/2a.hs new file mode 100644 index 0000000..b3dc505 --- /dev/null +++ b/src/2a/2a.hs @@ -0,0 +1,12 @@ +-- Напишите функцию (f s n), которая из двухуровневого +-- списка чисел s создает новый одноуровневый список квадратов +-- чисел, исключив все элементы исходного списка s, которые +-- меньше заданного числа n. + +f :: [[Int]] -> Int -> [Int] +f s n = [x*x | xs <- s, x <- xs, x >= n] + +main :: IO () +main = do + let s = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] + print $ f s 5 \ No newline at end of file diff --git a/src/2b/2b.hs b/src/2b/2b.hs new file mode 100644 index 0000000..c7e19e6 --- /dev/null +++ b/src/2b/2b.hs @@ -0,0 +1,12 @@ +-- Определите функцию (f a n), которая от двух числовых +-- аргументов строит следующий список: +-- [a, a*(a+1),a*(a+1)*(a+2),…,a*(a+1)*(a+2)*…*(a+n)]. + +f :: Int -> Int -> [Int] +f a n = scanl (*) a $ take n [a+1..] + +main :: IO () +main = do + let a = 2 + let n = 5 + print $ f a n diff --git a/src/3/3.hs b/src/3/3.hs new file mode 100644 index 0000000..5db08f7 --- /dev/null +++ b/src/3/3.hs @@ -0,0 +1,62 @@ +-- Определите тип данных для хранения следующей информации по +-- футбольным командам: название команды; информация по +-- результатам сыгранных игр – [(x1,y1), (x2,y2), …], где каждый +-- кортеж – это информация по отдельной игре и xi – количество +-- забитых голов, yi – количество пропущенных голов. Определить +-- для этого типа функцию сравнения ‘==’ класса Eq, а также функции +-- ‘<’, ‘<=’ класса Ord, сравнивая команды по количеству набранных +-- очков (выигрыш=3, ничья=1), если у двух команд равное +-- количество набранных очков, то дальше сравнивают разницу между +-- количеством забитых и количеством пропущенных голов. + +import Data.List (sortBy) + +data FootballTeam = FootballTeam { + teamName :: String, + gameResults :: [(Int, Int)] +} deriving (Show) + +instance Eq FootballTeam where + team1 == team2 = team1Score == team2Score && team1Diff == team2Diff + where + team1Score = calculateScore team1 + team2Score = calculateScore team2 + team1Diff = calculateGoalDifference team1 + team2Diff = calculateGoalDifference team2 + +instance Ord FootballTeam where + compare team1 team2 + | team1Score < team2Score = LT + | team1Score > team2Score = GT + | team1Diff < team2Diff = LT + | team1Diff > team2Diff = GT + | otherwise = EQ + where + team1Score = calculateScore team1 + team2Score = calculateScore team2 + team1Diff = calculateGoalDifference team1 + team2Diff = calculateGoalDifference team2 + +calculateScore :: FootballTeam -> Int +calculateScore team = sum [3 | (x, y) <- gameResults team, x > y] + sum [1 | (x, y) <- gameResults team, x == y] + +calculateGoalDifference :: FootballTeam -> Int +calculateGoalDifference team = sum [x - y | (x, y) <- gameResults team] + +main :: IO () +main = do + let teams = [FootballTeam "Team1" [(2, 1), (1, 1), (0, 1)], -- score: 4, diff: 0 + FootballTeam "Team2" [(1, 2), (3, 1), (2, 2)], -- score: 4, diff: 1 + FootballTeam "Team3" [(1, 1), (2, 2), (3, 3)]] -- score: 3, diff: 0 + + putStr "Sorted teams: " + print $ map teamName $ sortBy compare teams + + let team1 = FootballTeam "Team1" [(2, 1), (1, 1), (0, 1)] -- score: 4, diff: 0 + let team2 = FootballTeam "Team2" [(2, 1), (1, 1), (0, 1)] -- score: 4, diff: 0 + let team3 = FootballTeam "Team3" [(2, 1), (2, 1), (0, 1)] -- score: 4, diff: 1 + + putStr "Equal team1 and team2: " + print $ team1 == team2 + putStr "Equal team1 and team3: " + print $ team1 == team3 diff --git a/src/4/4.hs b/src/4/4.hs new file mode 100644 index 0000000..76f6195 --- /dev/null +++ b/src/4/4.hs @@ -0,0 +1,68 @@ +-- В файлах хранится информация об актерах и фильмах в следующем +-- виде: актер(<фамилия>,<название_фильма>), +-- фильм(<название_фильма>,<жанр>,<год_выпуска>). Написать +-- программу, формирующую список актеров по жанрам (если актер +-- снимался в фильмах разных жанров, то определять его жанр исходя +-- из максимального количества ролей в фильмах одного жанра). + +import Text.Regex.Posix +import Data.List (nubBy, maximumBy, group, sort) +import Data.Ord (comparing) +import System.Directory (getCurrentDirectory) + +data Actor = Actor { + name :: String, + movieTitle :: String +} deriving (Show) + +data Movie = Movie { + title :: String, + genre :: String, + year :: String +} deriving (Show) + +--parseActorsTest :: String -> [[String]] +--parseActorsTest content = content =~ actorRegex :: [[String]] +-- where actorRegex = "actor\\(([^,]+),([^\\)]+)\\)" + +parseActors :: String -> [Actor] +parseActors content = map (\x -> Actor (x !! 1) (x !! 2)) (content =~ actorRegex :: [[String]]) + where actorRegex = "actor\\(([^,]+),([^\\)]+)\\)" + +parseMovies :: String -> [Movie] +parseMovies content = map (\x -> Movie (x !! 1) (x !! 2) (x !! 3)) (content =~ movieRegex :: [[String]]) + where movieRegex = "movie\\(([^,]+),([^,]+),([^\\)]+)\\)" + +actorsWithMoviesTitle :: [Actor] -> [(Actor, [String])] +actorsWithMoviesTitle actors = + [(actor, [title | movie <- movies, let title = movieTitle movie]) | + actor <- uniqueActors, + let movies = filter (\movie -> name actor == name movie) actors] + where uniqueActors = nubBy (\x y -> name x == name y) actors + +joinMoviesWithActors :: [Movie] -> [(Actor, [String])] -> [(Actor, [Movie])] +joinMoviesWithActors movies actors = + [(actor, [movie | movie <- movies, title movie `elem` movieTitles]) | (actor, movieTitles) <- actors] + +mostCommonGenre :: [Movie] -> String +mostCommonGenre = head . maximumBy (comparing length) . group . sort . map genre + +mostPopularGenreByActor :: [(Actor, [Movie])] -> [(Actor, String)] +mostPopularGenreByActor = map (\(a, ms) -> (a, mostCommonGenre ms)) + + +main :: IO () +main = do + + content <- readFile "src/4/data.txt" + + -- print $ parseActorsTest content + + let actors = parseActors content + movies = parseMovies content + acWithMovieTitles = actorsWithMoviesTitle actors + acWithMovies = joinMoviesWithActors movies acWithMovieTitles + mostPopularGenre = mostPopularGenreByActor acWithMovies + + putStrLn "Most popular genre by actor:" + mapM_ (\x -> putStrLn $ name (fst x) ++ " - " ++ snd x) mostPopularGenre diff --git a/src/4/4.old.hs b/src/4/4.old.hs new file mode 100644 index 0000000..3934f98 --- /dev/null +++ b/src/4/4.old.hs @@ -0,0 +1,47 @@ +import Text.Regex.Posix +import Data.List (nubBy, maximumBy, group, sort) +import Data.Ord (comparing) + +data Actor = Actor { + name :: String, + movieTitle :: String +} deriving (Show) + +data Movie = Movie { + title :: String, + genre :: String, + year :: String +} deriving (Show) + +parseActors :: String -> [Actor] +parseActors content = map (\x -> Actor (x !! 1) (x !! 2)) (content =~ actorRegex :: [[String]]) + where actorRegex = "actor\\(([^,]+),([^\\)]+)\\)" + +parseMovies :: String -> [Movie] +parseMovies content = map (\x -> Movie (x !! 1) (x !! 2) (x !! 3)) (content =~ movieRegex :: [[String]]) + where movieRegex = "movie\\(([^,]+),([^,]+),([^\\)]+)\\)" + +actorsWithMoviesTitle :: [Actor] -> [(Actor, [String])] +actorsWithMoviesTitle actors = uniqueActors + where uniqueActors = nubBy (\x y -> name (fst x) == name (fst y)) actorsWithMovies + actorsWithMovies = map (\x -> (x, map movieTitle (filter (\y -> name x == name y) actors))) actors + +joinMoviesWithActors :: [Movie] -> [(Actor, [String])] -> [(Actor, [Movie])] +joinMoviesWithActors movies actors = map (\x -> (fst x, map (\y -> head (filter (\z -> title z == y) movies)) (snd x))) actors + +mostPopularGenreByActor :: [(Actor, [Movie])] -> [(Actor, String)] +mostPopularGenreByActor actorsWithMovies = map (\x -> (fst x, mostCommonGenre (snd x))) actorsWithMovies + where mostCommonGenre movies = head $ maximumBy (\x y -> compare (length x) (length y)) $ group $ sort $ map genre movies + +main :: IO () +main = do + content <- readFile "data.txt" + + let actors = parseActors content + movies = parseMovies content + ac = actorsWithMoviesTitle actors + acWithMovies = joinMoviesWithActors movies ac + mostPopularGenre = mostPopularGenreByActor acWithMovies + + putStrLn "Most popular genre by actor:" + mapM_ (\x -> putStrLn $ name (fst x) ++ " - " ++ snd x) mostPopularGenre \ No newline at end of file diff --git a/src/4/data.txt b/src/4/data.txt new file mode 100644 index 0000000..c747557 --- /dev/null +++ b/src/4/data.txt @@ -0,0 +1,11 @@ +actor(ivanov,movie1) +actor(ivanov,movie2) +actor(ivanov,movie3) +actor(petrov,movie4) +actor(sidrov,movie1) + +movie(movie1,action,2000) +movie(movie2,comedy,2005) +movie(movie3,action,2010) +movie(movie4,drama,2020) +movie(movie5,action,2021)