haskell list of tuples, with unique tuples - list

I come from a Python and Java background so Haskell is quite different for me. I'm trying little activities to learn but I am stuck on this .
I have an ordered list of tuples, [(name, studentNumber)], and I want to filter this list so that each student and each studentNumber appears only once. Since the tuples are ordered, I want to keep the first instance of a name or studentNumber and remove any others that may show up.
I tried doing a list comphrenshion, but I'm not sure how to check if a name or number has already been added to the list.

It sounds as if you'd want (as a first, inefficient approximation) something like this:
import Data.List (nubBy)
import Data.Function (on)
filt = nubBy ((==) `on` snd) . nubBy ((==) `on` fst)
The first call to nubBy will result in a list in which each name appears only once, and that will then be passed to the second, resulting in a list in which each number appears only once.
Just using nub will result in a list in which each (name,number) pair occurs only once; there might still be repetitions of names with different numbers and numbers with different names.
(Of course something custom with an accumulator would be faster.)

You can spy on Data.List sources and write your extended nub function:
type Student = (Name, Number)
type Name = String
type Number = Int
unique :: [Student] -> [Student]
unique = go [] []
where
go unames unumbers (s#(name, number):ss)
| name `elem` unames || number `elem` unumbers = go unames unumbers ss
| otherwise = s : go (name:unames) (number:unumbers) ss
go _ _ [] = []
Should do what you want.

To unique-ify a list there's always the nub function from the prelude, I think that should do exactly what you need!

Related

Sort a list of tuples by their second element without higher order functions or recursion

I have a list of (String, Int) pairs and am struggling to figure out how to sort the list by the snd field (Int). I am not allowed to use higher order functions or recursion which makes it more difficult.
For example, I have
[("aaaaa", 5),("bghdfe", 6),("dddr",4)]
and would like to sort it into
[("dddr",4),("aaaaa", 5),("bghdfe", 6)].
Edit:
I understand that the sort may not be possible without higher order functions, what I really need is to find the element with the minimum length (the snd field), so is there a way to find the minimum number and then take the fst field of the list's element at that index? If that way works better I am unsure about how to find the index of that minimum number however.
The task seems to be impossible, since you can't write a sort without recursion in Haskell. This means, you must use sort, which is usually something like sortBy compare and thus you have it.
But if you are allowed to use sort you can do it by first reversing all tuples, sorting the resulting list and reversing the tuples in the result again. This should be possible to do in a few nested list comprehension, so technically no higher order functions are needed.
After you have given more details, I'd do
homework list = snd (minimum [ (s,f) | (f,s) <- list ])
Without higher order functions or recursion all you have left, technically, is list comprehensions. Thus we define
-- sortBy (comparing snd) >>> take 1 >>> listToMaybe >>> fmap fst
-- ~= minimumBy (comparing snd) >>> fst
foo :: Ord b => [(a,b)] -> Maybe a
foo xs = case [ a | (a,b) <- xs
, null [ () | (_c,d) <- xs, d < b]]
of (a:_) -> Just a
[] -> Nothing

Haskell : Filter list for elements of second list

I am currently trying to filter a list , that consist of tuples of the form (String , Double), for a List that consists of Strings. If the tuple doesn't contain a String of the second list, it should be removed from the list of tuples. So far I came up with this:
test :: [ExamScore] -> String -> [ExamScore]
test a b = filter ((== b).fst) a
My current problem is to replace the String that is filtered for by a list of Strings. Thanks for your help! Please go easy on me, I'm a first year informatics student that hasn't coded anytime before.
It's almost the same, just another filter function using elem:
test a b :: [ExamScore] -> [String] -> [ExamScore]
test a b = filter (\(s, _) -> elem s b) a
Or, if you're more into the composition style:
test a b = filter (flip elem b . fst) a
(It's worth noting that it's not the most efficient way, since elem is O(N) for lists, so depending on your case you may want to find a better structure for storing the keys.)

Grouping a list into lists of n elements in Haskell

Is there an operation on lists in library that makes groups of n elements? For example: n=3
groupInto 3 [1,2,3,4,5,6,7,8,9] = [[1,2,3],[4,5,6],[7,8,9]]
If not, how do I do it?
A quick search on Hoogle showed that there is no such function. On the other hand, it was replied that there is one in the split package, called chunksOf.
However, you can do it on your own
group :: Int -> [a] -> [[a]]
group _ [] = []
group n l
| n > 0 = (take n l) : (group n (drop n l))
| otherwise = error "Negative or zero n"
Of course, some parentheses can be removed, I left there here for understanding what the code does:
The base case is simple: whenever the list is empty, simply return the empty list.
The recursive case tests first if n is positive. If n is 0 or lower we would enter an infinite loop and we don't want that. Then we split the list into two parts using take and drop: take gives back the first n elements while drop returns the other ones. Then, we add the first n elements to the list obtained by applying our function to the other elements in the original list.
This function, among other similar ones, can be found in the popular split package.
> import Data.List.Split
> chunksOf 3 [1,2,3,4,5,6,7,8,9]
[[1,2,3],[4,5,6],[7,8,9]]
You can write one yourself, as Mihai pointed out. But I would use the splitAt function since it doesn't require two passes on the input list like the take-drop combination does:
chunks :: Int -> [a] -> [[a]]
chunks _ [] = []
chunks n xs =
let (ys, zs) = splitAt n xs
in ys : chunks n zs
This is a common pattern - generating a list from a seed value (which in this case is your input list) by repeated iteration. This pattern is captured in the unfoldr function. We can use it with a slightly modified version of splitAt (thanks Will Ness for the more concise version):
chunks n = takeWhile (not . null) . unfoldr (Just . splitAt n)
That is, using unfoldr we generate chunks of n elements while at the same time we shorten the input list by n elements, and we generate these chunks until we get the empty list -- at this point the initial input is completely consumed.
Of course, as the others have pointed out, you should use the already existing function from the split module. But it's always good to accustom yourself with the list processing functions in the standard Haskell libraries.
This is ofte called "chunk" and is one of the most frequently mentioned list operations that is not in base. The package split provides such an operation though, copy and pasting the haddock documentation:
> chunksOf 3 ['a'..'z']
["abc","def","ghi","jkl","mno","pqr","stu","vwx","yz"]
Additionally, against my wishes, hoogle only searches a small set of libraries (those provided with GHC or perhaps HP), but you can explicitly add packages to the search using +PKG_NAME - hoogle with Int -> [a] -> [[a]] +split gets what you want. Some people use Hayoo for this reason.

Haskell - Convert x number of tuples into a list [duplicate]

I have a question about tuples and lists in Haskell. I know how to add input into a tuple a specific number of times. Now I want to add tuples into a list an unknown number of times; it's up to the user to decide how many tuples they want to add.
How do I add tuples into a list x number of times when I don't know X beforehand?
There's a lot of things you could possibly mean. For example, if you want a few copies of a single value, you can use replicate, defined in the Prelude:
replicate :: Int -> a -> [a]
replicate 0 x = []
replicate n | n < 0 = undefined
| otherwise = x : replicate (n-1) x
In ghci:
Prelude> replicate 4 ("Haskell", 2)
[("Haskell",2),("Haskell",2),("Haskell",2),("Haskell",2)]
Alternately, perhaps you actually want to do some IO to determine the list. Then a simple loop will do:
getListFromUser = do
putStrLn "keep going?"
s <- getLine
case s of
'y':_ -> do
putStrLn "enter a value"
v <- readLn
vs <- getListFromUser
return (v:vs)
_ -> return []
In ghci:
*Main> getListFromUser :: IO [(String, Int)]
keep going?
y
enter a value
("Haskell",2)
keep going?
y
enter a value
("Prolog",4)
keep going?
n
[("Haskell",2),("Prolog",4)]
Of course, this is a particularly crappy user interface -- I'm sure you can come up with a dozen ways to improve it! But the pattern, at least, should shine through: you can use values like [] and functions like : to construct lists. There are many, many other higher-level functions for constructing and manipulating lists, as well.
P.S. There's nothing particularly special about lists of tuples (as compared to lists of other things); the above functions display that by never mentioning them. =)
Sorry, you can't1. There are fundamental differences between tuples and lists:
A tuple always have a finite amount of elements, that is known at compile time. Tuples with different amounts of elements are actually different types.
List an have as many elements as they want. The amount of elements in a list doesn't need to be known at compile time.
A tuple can have elements of arbitrary types. Since the way you can use tuples always ensures that there is no type mismatch, this is safe.
On the other hand, all elements of a list have to have the same type. Haskell is a statically-typed language; that basically means that all types are known at compile time.
Because of these reasons, you can't. If it's not known, how many elements will fit into the tuple, you can't give it a type.
I guess that the input you get from your user is actually a string like "(1,2,3)". Try to make this directly a list, whithout making it a tuple before. You can use pattern matching for this, but here is a slightly sneaky approach. I just remove the opening and closing paranthesis from the string and replace them with brackets -- and voila it becomes a list.
tuplishToList :: String -> [Int]
tuplishToList str = read ('[' : tail (init str) ++ "]")
Edit
Sorry, I did not see your latest comment. What you try to do is not that difficult. I use these simple functions for my task:
words str splits str into a list of words that where separated by whitespace before. The output is a list of Strings. Caution: This only works if the string inside your tuple contains no whitespace. Implementing a better solution is left as an excercise to the reader.
map f lst applies f to each element of lst
read is a magic function that makes a a data type from a String. It only works if you know before, what the output is supposed to be. If you really want to understand how that works, consider implementing read for your specific usecase.
And here you go:
tuplish2List :: String -> [(String,Int)]
tuplish2List str = map read (words str)
1 As some others may point out, it may be possible using templates and other hacks, but I don't consider that a real solution.
When doing functional programming, it is often better to think about composition of operations instead of individual steps. So instead of thinking about it like adding tuples one at a time to a list, we can approach it by first dividing the input into a list of strings, and then converting each string into a tuple.
Assuming the tuples are written each on one line, we can split the input using lines, and then use read to parse each tuple. To make it work on the entire list, we use map.
main = do input <- getContents
let tuples = map read (lines input) :: [(String, Integer)]
print tuples
Let's try it.
$ runghc Tuples.hs
("Hello", 2)
("Haskell", 4)
Here, I press Ctrl+D to send EOF to the program, (or Ctrl+Z on Windows) and it prints the result.
[("Hello",2),("Haskell",4)]
If you want something more interactive, you will probably have to do your own recursion. See Daniel Wagner's answer for an example of that.
One simple solution to this would be to use a list comprehension, as so (done in GHCi):
Prelude> let fstMap tuplist = [fst x | x <- tuplist]
Prelude> fstMap [("String1",1),("String2",2),("String3",3)]
["String1","String2","String3"]
Prelude> :t fstMap
fstMap :: [(t, b)] -> [t]
This will work for an arbitrary number of tuples - as many as the user wants to use.
To use this in your code, you would just write:
fstMap :: Eq a => [(a,b)] -> [a]
fstMap tuplist = [fst x | x <- tuplist]
The example I gave is just one possible solution. As the name implies, of course, you can just write:
fstMap' :: Eq a => [(a,b)] -> [a]
fstMap' = map fst
This is an even simpler solution.
I'm guessing that, since this is for a class, and you've been studying Haskell for < 1 week, you don't actually need to do any input/output. That's a bit more advanced than you probably are, yet. So:
As others have said, map fst will take a list of tuples, of arbitrary length, and return the first elements. You say you know how to do that. Fine.
But how do the tuples get into the list in the first place? Well, if you have a list of tuples and want to add another, (:) does the trick. Like so:
oldList = [("first", 1), ("second", 2)]
newList = ("third", 2) : oldList
You can do that as many times as you like. And if you don't have a list of tuples yet, your list is [].
Does that do everything that you need? If not, what specifically is it missing?
Edit: With the corrected type:
Eq a => [(a, b)]
That's not the type of a function. It's the type of a list of tuples. Just have the user type yourFunctionName followed by [ ("String1", val1), ("String2", val2), ... ("LastString", lastVal)] at the prompt.

How do I add x tuples into a list x number of times?

I have a question about tuples and lists in Haskell. I know how to add input into a tuple a specific number of times. Now I want to add tuples into a list an unknown number of times; it's up to the user to decide how many tuples they want to add.
How do I add tuples into a list x number of times when I don't know X beforehand?
There's a lot of things you could possibly mean. For example, if you want a few copies of a single value, you can use replicate, defined in the Prelude:
replicate :: Int -> a -> [a]
replicate 0 x = []
replicate n | n < 0 = undefined
| otherwise = x : replicate (n-1) x
In ghci:
Prelude> replicate 4 ("Haskell", 2)
[("Haskell",2),("Haskell",2),("Haskell",2),("Haskell",2)]
Alternately, perhaps you actually want to do some IO to determine the list. Then a simple loop will do:
getListFromUser = do
putStrLn "keep going?"
s <- getLine
case s of
'y':_ -> do
putStrLn "enter a value"
v <- readLn
vs <- getListFromUser
return (v:vs)
_ -> return []
In ghci:
*Main> getListFromUser :: IO [(String, Int)]
keep going?
y
enter a value
("Haskell",2)
keep going?
y
enter a value
("Prolog",4)
keep going?
n
[("Haskell",2),("Prolog",4)]
Of course, this is a particularly crappy user interface -- I'm sure you can come up with a dozen ways to improve it! But the pattern, at least, should shine through: you can use values like [] and functions like : to construct lists. There are many, many other higher-level functions for constructing and manipulating lists, as well.
P.S. There's nothing particularly special about lists of tuples (as compared to lists of other things); the above functions display that by never mentioning them. =)
Sorry, you can't1. There are fundamental differences between tuples and lists:
A tuple always have a finite amount of elements, that is known at compile time. Tuples with different amounts of elements are actually different types.
List an have as many elements as they want. The amount of elements in a list doesn't need to be known at compile time.
A tuple can have elements of arbitrary types. Since the way you can use tuples always ensures that there is no type mismatch, this is safe.
On the other hand, all elements of a list have to have the same type. Haskell is a statically-typed language; that basically means that all types are known at compile time.
Because of these reasons, you can't. If it's not known, how many elements will fit into the tuple, you can't give it a type.
I guess that the input you get from your user is actually a string like "(1,2,3)". Try to make this directly a list, whithout making it a tuple before. You can use pattern matching for this, but here is a slightly sneaky approach. I just remove the opening and closing paranthesis from the string and replace them with brackets -- and voila it becomes a list.
tuplishToList :: String -> [Int]
tuplishToList str = read ('[' : tail (init str) ++ "]")
Edit
Sorry, I did not see your latest comment. What you try to do is not that difficult. I use these simple functions for my task:
words str splits str into a list of words that where separated by whitespace before. The output is a list of Strings. Caution: This only works if the string inside your tuple contains no whitespace. Implementing a better solution is left as an excercise to the reader.
map f lst applies f to each element of lst
read is a magic function that makes a a data type from a String. It only works if you know before, what the output is supposed to be. If you really want to understand how that works, consider implementing read for your specific usecase.
And here you go:
tuplish2List :: String -> [(String,Int)]
tuplish2List str = map read (words str)
1 As some others may point out, it may be possible using templates and other hacks, but I don't consider that a real solution.
When doing functional programming, it is often better to think about composition of operations instead of individual steps. So instead of thinking about it like adding tuples one at a time to a list, we can approach it by first dividing the input into a list of strings, and then converting each string into a tuple.
Assuming the tuples are written each on one line, we can split the input using lines, and then use read to parse each tuple. To make it work on the entire list, we use map.
main = do input <- getContents
let tuples = map read (lines input) :: [(String, Integer)]
print tuples
Let's try it.
$ runghc Tuples.hs
("Hello", 2)
("Haskell", 4)
Here, I press Ctrl+D to send EOF to the program, (or Ctrl+Z on Windows) and it prints the result.
[("Hello",2),("Haskell",4)]
If you want something more interactive, you will probably have to do your own recursion. See Daniel Wagner's answer for an example of that.
One simple solution to this would be to use a list comprehension, as so (done in GHCi):
Prelude> let fstMap tuplist = [fst x | x <- tuplist]
Prelude> fstMap [("String1",1),("String2",2),("String3",3)]
["String1","String2","String3"]
Prelude> :t fstMap
fstMap :: [(t, b)] -> [t]
This will work for an arbitrary number of tuples - as many as the user wants to use.
To use this in your code, you would just write:
fstMap :: Eq a => [(a,b)] -> [a]
fstMap tuplist = [fst x | x <- tuplist]
The example I gave is just one possible solution. As the name implies, of course, you can just write:
fstMap' :: Eq a => [(a,b)] -> [a]
fstMap' = map fst
This is an even simpler solution.
I'm guessing that, since this is for a class, and you've been studying Haskell for < 1 week, you don't actually need to do any input/output. That's a bit more advanced than you probably are, yet. So:
As others have said, map fst will take a list of tuples, of arbitrary length, and return the first elements. You say you know how to do that. Fine.
But how do the tuples get into the list in the first place? Well, if you have a list of tuples and want to add another, (:) does the trick. Like so:
oldList = [("first", 1), ("second", 2)]
newList = ("third", 2) : oldList
You can do that as many times as you like. And if you don't have a list of tuples yet, your list is [].
Does that do everything that you need? If not, what specifically is it missing?
Edit: With the corrected type:
Eq a => [(a, b)]
That's not the type of a function. It's the type of a list of tuples. Just have the user type yourFunctionName followed by [ ("String1", val1), ("String2", val2), ... ("LastString", lastVal)] at the prompt.