1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
-- Originally done here: https://github.com/Syndamia/IT-kariera/blob/master/Year%203/Functional%20programming/Exam%20preparation/LINQuistics.hs
-- At the bottom you can find the problem this solves (Note: it was originally made for C# with Linq)
{- Split -}
splitAtSection :: String -> Int -> [Int]
splitAtSection str start = if start == length str then [start, 0]
else if str!!start == '.' then [start, 1]
else if str!!start == '(' then [start, 3]
else splitAtSection str (start + 1)
splitInput :: String -> [String]
splitInput line = if null line then []
else [take (head (splitAtSection line 0)) line] ++ splitInput (drop (sum (splitAtSection line 0)) line)
{- Insert -}
sanitizeArr :: Eq a => [a] -> [a]
sanitizeArr arr = if null arr then []
else if elem (last arr) (init arr) then sanitizeArr (init arr)
else (sanitizeArr (init arr)) ++ [last arr]
insertIncl :: [[String]] -> [String] -> [[String]]
insertIncl mat info = if indexOfHead mat (head info) 0 < 0
then mat ++ [[head info] ++ sanitizeArr (tail info)]
else insertInfo mat (indexOfHead mat (head info) 0) (tail info)
where insertInfo mat index info = take index mat ++ [[head (mat!!index)] ++ sanitizeArr ((tail (mat!!index)) ++ info)] ++ drop (index + 1) mat
{- Sort -}
desc :: (Ord a) => [a] -> (a -> a -> Bool) -> (a -> a -> Bool) -> Int -> Int -> [a]
desc arr cond scond end curr = if end == 0 then arr
else if curr == end then desc arr cond scond (end - 1) 0
else if cond (arr!!curr) (arr!!(curr + 1)) || scond (arr!!curr) (arr!!(curr+1))
then desc (swapTwo arr curr) cond scond end (curr + 1)
else desc arr cond scond end (curr + 1)
where swapTwo arr i = take i arr ++ [arr!!(i + 1)] ++ [arr!!i] ++ drop (i + 2) arr
orderByDesc :: (Ord a) => [a] -> (a -> a -> Bool) -> (a -> a -> Bool) -> [a]
orderByDesc arr cond scond = desc arr cond scond (length arr - 1) 0
{- Sort conditions -}
compByUniqCnt :: String -> String -> Bool
compByUniqCnt x y = length x == length y && uniqCnt x < uniqCnt y
where uniqCnt str = length (foldl (\acc x -> if elem x acc then acc else acc ++ [x]) [] str)
compByLen :: (Ord a) => [a] -> [a] -> Bool
compByLen x y = length x < length y
compByShort :: (Ord a) => [a] -> [a] -> Bool
compByShort x y = length x > length y
compByShortestName :: [String] -> [String] -> Bool
compByShortestName x y = length (last (orderByDesc (tail x) compByLen alwaysFalse)) < length (last (orderByDesc (tail y) compByLen alwaysFalse))
alwaysFalse :: a -> a -> Bool
alwaysFalse x y = False
{- Filters -}
elemsThatContain :: [[String]] -> String -> [[String]]
elemsThatContain mat item = if null mat then []
else if elem item (head mat) then [head mat] ++ elemsThatContain (tail mat) item
else elemsThatContain (tail mat) item
getCollWithMostMethods :: [[String]] -> [String]
getCollWithMostMethods mat = mat!!(indexOfMostMethods lengthsArr)
where lengthsArr = map (\x -> length x) mat
indexOfMostMethods arr = foldl (\acc x -> if arr!!x > arr!!acc then x else acc) 0 [1..(length mat - 1)]
{- Printing -}
printMethods arr =
if null arr then return ()
else do
putStrLn ("* " ++ (head arr))
printMethods (tail arr)
printCollection :: [[String]] -> Bool -> IO ()
printCollection collection haveMethods = do
if null collection then return ()
else do
putStrLn (head (head collection))
if haveMethods
then printMethods (orderByDesc (tail (head collection)) compByLen alwaysFalse)
else return ()
printCollection (tail collection) haveMethods
{- Main -}
indexOfHead :: [[String]] -> String -> Int -> Int
indexOfHead mat key start = if null mat then (-1)
else if head (head mat) == key then start
else indexOfHead (tail mat) key (start + 1)
isNumber :: String -> Bool
isNumber str = if null str then False
else (head str >= '0' && head str <= '9') && ((length str > 1) == isNumber (tail str))
readUntilWord :: [[String]] -> IO ()
readUntilWord mat = do
line <- getLine
let coll = splitInput line
if head coll == "exit" then do
final <- getLine
let comm = words final
let collecs = elemsThatContain mat (head comm)
let ordered = orderByDesc collecs compByLen compByShortestName
printCollection ordered (comm!!1 == "all")
else if length coll == 1 then do
if isNumber (head coll) then do
let mostMethodsOrd = orderByDesc (tail (getCollWithMostMethods mat)) compByShort alwaysFalse
let n = read (head coll) :: Int
printMethods (take n mostMethodsOrd)
else if indexOfHead mat (head coll) 0 >= 0 then do
let methods = orderByDesc (tail (mat!!(indexOfHead mat (head coll) 0))) compByLen compByUniqCnt
printMethods methods
else return()
readUntilWord mat
else readUntilWord (insertIncl mat coll)
main :: IO()
main = do
readUntilWord []
--
-- LINQuistics
--
-- LINQ is the greatest .NET component of all time. You can do almost anything with it. That’s why you have been tasked to do almost everything you can with it.
--
-- ---------
-- - Input -
-- ---------
--
-- You will be given several input lines containing information about collections, and LINQ methods that have been called on them, in the following format:
--
-- {collection}.{method1}().{method2}()....{methodN}()
--
-- The count of methods may vary. Your task is to store every collection and the methods that have been executed on it.
-- If the collection already exists, you must ADD the new methods to it. Duplicate methods should be REMOVED.
--
-- ----------
-- - Output -
-- ----------
--
-- If you are given only a collection name, you must print the methods that have been executed on the collection, ordered by their length in descending order.
-- If 2 methods have the same length, order them by the count of unique symbols they have in their names in descending order.
--
-- Each method must be printed on a new line, with a prefixed asterisk and space (“* ”).
--
-- If the collection name does NOT exist, you should IGNORE that line of input.
--
-- If you are given only a digit, you must take the collection which has the most methods, and print the first N methods, with the lowest length (N being the digit given in the input).
-- If there are less than N methods you must print all of them in the same order.
--
-- NOTE: When printing, you must print only the method name, without its brackets (e.g. “First”, not “First()”).
--
-- The input sequence ends when you receive the command “exit”. After the ending command, you will receive one last line in the following format:
--
-- {method} {selection}
--
-- You must take all collections, which CONTAIN the given method, and print them. The selection will either be “collection” or “all”.
-- If you have “collection”, you must print only the collections’ names in the final output.
-- If you have “all”, you must print the collections and their methods in the following format:
--
-- {collection}
-- * {method1}
-- * {method2}
-- ...
--
-- The collections must be printed ordered by the count of their methods in descending order.
--
-- If 2 collections have the same amount of methods, print the one whose shortest method name is longer than the other one’s shortest method name.
--
-- The methods must be printed, ordered by their length in descending order.
--
-- ------------
-- - Examples -
-- ------------
--
-- -- Input -------------------------------
-- participants.Max().Reverse().ThenBy()
-- participants.OrderBy.Select()
-- participants
-- participants.ToDictionary()
-- collection.Max()
-- collection.Break()
-- exit
-- Max all
-- -- Output ------------------------------
-- * OrderBy
-- * Reverse
-- * ThenBy
-- * Select
-- * Max
-- participants
-- * ToDictionary
-- * Reverse
-- * OrderBy
-- * ThenBy
-- * Select
-- * Max
-- collection
-- * Break
-- * Max
--
-- -- Input -------------------------------
-- elements.Sort()
-- elements.OrderBy()
-- bound
-- elements.Reverse().Select().ThenBy()
-- keys.Reverse().OrderByDescending()
-- keys.Reverse().ThenByDescending()
-- 3
-- keys.Reverse().OrderBy().ThenBy()
-- values.ToString().ToString().ThenBy()
-- exit
-- Reverse collection
-- -- Output ------------------------------
-- * Sort
-- * Select
-- * ThenBy
-- keys
-- elements
|