How to apply function to vector list? - haskell

I have a large nested vector that look like this:
import Data.Vector
let x = fromList [["a", "b", "12", "d"], ["e", "f", "34", "g"]...]
I would like to convert the strings to integers at position 2 in each nested list I was trying to do this with map and a comprehension like this:
let y = Data.Vector.map (\a -> read a :: Int) [i !! 2 | i <- x]
What am I doing wrong? I would like the output to be:
(("a", "b", 12, "d"), ("e", "f", 34, "g")...)

There are a number of problems here.
First of all, the result of a list comprehension is a list, so you're calling Data.Vector.map on a list, which won't work. And the x inside the comprehension is a Vector, which is another type mismatch. Either use a list instead of a Vector (along with Prelude.map) or convert the list to a Vector (in which case you can't use a list comprehension).
Secondly, ignoring the list/Vector problem, [i !! 2 | i <- x] will give you a list containing only the elements at position 2 from each sub-list. Using your example, the comprehension would yield ["12", "34"]. Then when you map read over it, you'll get [12, 34], rather than the output you're shooting for.
Finally, the output you're wanting to see is not valid for lists or for Vectors in Haskell. Both types of container must be homogeneous, i.e. they cannot contain values of more than one type. A [Int] cannot contain Strings, nor can a [String] contain Ints, but your desired output contains both. There are ways you can get around this using existential types, but chances are there's a better solution for your underlying problem than to try to build heterogeneous collections.
Edit: You edited the last part of your post to use tuples, so the above paragraph no longer applies. The first two problems I mentioned still exist, though.
If you start with a list of 4-tuples ([(String, String, String, String)]), you can get what you want like this:
> let x = [("a", "b", "12", "d"), ("e", "f", "34", "g")]
> map (\(a, b, c, d) -> (a, b, read c :: Int, d)) x
[("a", "b", 12, "d"), ("e", "f", 34, "g")]

It looks much like you should use a more sophisticated data type than a 4-tuple, like
data YourType_StringNum = YourType_StringNum { ytsnLetters1 :: String
, ytsnLetters2 :: String
, ytsnNumber :: String
, ytsnLetters3 :: String }
data YourType_IntNum = YourType_IntNum { ytinLetters1 :: String
, ytinLetters2 :: String
, ytinNumber :: Int
, ytinLetters3 :: String }
(of course with better identifiers). Then define a function like
toYtin :: YourType_StringNum -> YourType_IntNum
toYtin(YourType_StringNum a b s c) = YourType_IntNum a b (read s) c
With that, your problem reduces to transforming a Vector YourType_StringNum to a Vector YourType_IntNum, and that's trivially done with Data.Vector.map toYtin.

Related

haskell comprehension list, compare string with list and create string list with values, from list

I am new haskell. I want always check the first element from the string and compare the string with Char value from the list. So firstly I will compare "H" with 'E', then "H" with 'F', then "H" with 'G', and last "H" with 'H'. And if "H" = 'H' so I want add to my output string value of list element, in my case for 'H' it is "GG". But If all four are not equal so I want add to list current character in my case "A".
So I want my output to look like this ["GG","A","GG","A"]
Do you know some solution ?
My code:
findc :: String -> [(Char, String)] -> [String]
findc str list =
let filtered = [ if inputChar `elem` [(str !! num)] then decodedValue else if inputChar /= (str !! num) then [(str !! num)] else [] | num<-[0..(length str)-1],(inputChar,decodedValue) <- list]
in filtered
input:
findc "HAHA" [('E', "AB"), ('F', "CD"), ('G', "EF"), ('H', "GG")]
bad output:
["H","H","H","GG","A","A","A","A","H","H","H","GG","A","A","A","A"]
Your function is using a list comprehension with effectively nested loops. It loops over the indices of the string and then over the elements in the list of tuples you've passed in. Both contain 4 elements, so it's natural that your list comprehension iterates 16 times and you end up with 16 elements in your incorrect output.
A simpler, correct approach
[(Char, String)] describes a lookup table.
Fortunately, Haskell gives us the lookup function.
:ghci> :t lookup
lookup :: Eq a => a -> [(a, b)] -> Maybe b
ghci> tbl = [('E', "AB"), ('F', "CD"), ('G', "EF"), ('H', "GG")]
ghci> lookup 'H' tbl
Just "GG"
ghci> lookup 'A' tbl
Nothing
Now, you just need to map this to your string in a list comprehension, handling the Just case differently from the Nothing case.
ghci> [case lookup ch tbl of {Just s -> ...; Nothing -> ...} | ch <- "HAHA"]
["GG","A","GG","A"]
Using Data.Maybe.maybe
Unsurprisingly the Data.Maybe library has fucntions for dealing with Maybe values like those returned by lookup.
case expr1 of { Just x -> expr2; Nothing -> expr3 }
Can be expressed as:
maybe expr3 (\x -> expr2) expr1
So we can write:
ghci> [maybe ... ... $ lookup ch tbl | ch <- "HAHA"]
["GG","A","GG","A"]

Check tuple to see if there are different values assigned for same element in lists

New to Haskell and trying to solve a problem.
I am making a function conflicts with the signature conflicts :: Tuples -> Bool where Tuples is type Tuples = [(Char,Int)]. Purpose of this function is to check whether or not the same character has been assigned a different integer and return false if same characters are given different conflicting values - e.g conflicts [('d', 2), ('f', 1)] would return True, as f and d are separate characters assigned different values. However, conflicts [('f', 2), ('f', 1)] would return False, as 'f' has been assigned to 2 and 1. Also, conflicts [('f', 2), ('f', 2)] would return True, as f is assigned the value 2 on both occasions - so there is no conflict in the values. conflicts [('f', 2), ('f', 2), ('c', 6), ('d', 4)] would return False and so on.
So far, I've tried the below, but it doesn't always the produce the expected output. I think it only checks if at least one pair of lists have the same character and integer - if this is the case, it returns True. However, this isn't the output I'm looking for; I also want to check the conditions where the character is the same, but they have different integers (therefore should return False).
conflicts:: Tuples -> Bool; conflicts = \case { [] -> True; x:xs -> any (== x) xs}
If anyone can help solve this, I'd appreciate it greatly. Thanks.
Your solution checks whether the tail xs of the list contains a tuple equal to the head x (i.e. the same character and integer).
You can modify it to find a tuple with the same character, using lookup :: Eq a => a -> [(a,b)] -> Maybe b. Also, even if there is no conflicts for the first element, you have to continue looking for conflicts in the tail and call your function recursively (imagine a list [('a',0),('b',1),('b',2)]).
Finally, the solution looks like this:
{-# LANGUAGE LambdaCase #-}
type Tuples = [(Char, Int)]
conflicts :: Tuples -> Bool
conflicts = \case
[] -> False -- empty list has no conflicts
(x,c) : tuples -> case lookup x tuples of
Nothing -> conflicts tuples -- no `x` in the rest of list, continue checks
Just d
| c /= d -> True -- found a conflict
| otherwise -> conflicts tuples -- the same assignment, continue checks
Here I used pattern matching to extract the character x and its assignment c.

Haskell find and replace values from list using map

I have a list of lists in single chars like: [["a"],["b"],["c"],["d"]],
and I have a map for example [("a", "A"), ("b", "B")], I would like to find elements in list that match the map keys and replace the list value with the map value for that key and remove all of the remaining unchanged single chars.
So for example from the above, if I have list of [["a"],["b"],["c"],["d"]] and map of [("a", "A"), ("b", "B")] I want to get back a single list like this: ["A", "B"]
As I am a total noob with Haskell so any help will be appreciated :)
You can combine lookup with catMaybes:
import Data.Maybe
list :: [[String]]
list = [["a"],["b"],["c"],["d"]]
replacements :: [(String, String)]
replacements = [("a", "A"), ("b", "B")]
replaced :: [String]
replaced = catMaybes . map (\x -> lookup x replacements) . concat $ list
main :: IO ()
main = print replaced -- ["A", "B"]

Creating new fromList from fromList with "keys"

Trying to work out a solution to this problem..
Let's say I have x = fromList[("a", 1), ("b", 2), ("c", 3)]
And have a list ["a", "a", "b", "c" , "c"]
How would I think about producing something like..
Map.fromList[("a", 2), ("b", 2), ("c", 6)]
Any help leading in the right direction would be greatly appreciated
I'm starting from the assumption in K. A. Buhr's comment that you want to obtain the product of the counts in the original hash and the hash originating from the input list.
For this we need a function occurrences which transforms a list of strings into a hash from string to number of occurrences. This can easily be done using the insertWith function, which combines a the value to be inserted with the stored values using the given operation if a stored value exists and otherwise just inserts.
To multiply the occurrences with the existing hash, we use the unionWith function which works in a similar way as insertWith in the sense that it forms the union using a given operation if the element exists in both hashes and otherwise just inserts.
{-# OPTIONS_GHC -Wall #-}
import Data.Map
x :: Map String Int
x = fromList [("a", 1), ("b", 2), ("c", 3)]
occurrences :: Ord k => [k] -> Map k Int
occurrences l = aux l empty
where
aux [] h = h
aux (a:as) h = aux as $ insertWith (+) a 1 h
main :: IO ()
main = print $ unionWith (*) x $ occurrences ["a", "a", "b", "c", "c"]
Live example on Wandbox

Using list comprehensions to remove a list element by index

A table is a list of lists, where the data is set up as follows:
data Position = CEO | Manager| Programmer | Intern deriving (Eq, Show)
data Field = EmployeeID Int | T Position | Name String | Salary Int deriving (Eq)
instance Show Field where
show (EmployeeID k) = show k
show (T p) = show p
show (Name s) = s
show (Salary k) = show k
type Column = Int
type Row = [Field]
type Table = [Row]
An example table would look like this:
employees = [[EmployeeID 1, Name "Shoo"],
[EmployeeID 2, Name "Barney"],
[EmployeeID 3, Name "Brown"],
[EmployeeID 4, Name "Gold"],
[EmployeeID 5, Name "Sky"]]
How would I go about using a list comprehension to create a function that removes a column from the table? I do not know how to operate on lists of lists. I need to have the function have a type of delete :: Column -> Row -> Row
If I were to implement this without list comprehensions, I'd use map and filter.
Happily, you can easily do both of those with list comprehensions.
I'm going to avoid using your code, but as an example, suppose I had the list of lists:
nameSets = [[ "dave", "john", "steve"]
,[ "mary", "beth", "joan" ]
,[ "daren", "edward" ]
,[ "riley"]
]
And I wanted to get excited versions of all the lists with three elements:
[ [ name ++ "!" | name <- nameSet ] | nameSet <- nameSets, length nameSet == 3 ]
-- [[ "dave!", "john!", "steve!"]
-- ,[ "mary!", "beth!", "joan!" ]
-- ]
Edit: Just noticed that your column is specified by index. In that case, a zip is useful, which can also be done with list comprehensions, but a language extension is needed.
In a source file, put {-# LANGUAGE ParallelListComp #-} at the top to do zips in list comprehensions.
Here's how they work:
% ghci -XParallelListComp
ghci> [ (x,y) | x <- "abcdef" | y <- [0..5] ]
[('a',0),('b',1),('c',2),('d',3),('e',4),('f',5)]
Or, without the extension
% ghci
ghci> [ (x,y) | (x,y) <- zip "abcdef" [0..5] ]
[('a',0),('b',1),('c',2),('d',3),('e',4),('f',5)]
List comprehension does not work very well for removing by index, but here's a try (homework adjusted):
deleteAt :: Column -> Row -> Row
deleteAt n r = [e|(i,e) <- zip (a list of all indexes) r, test i] where
test i = (True if index i should be kept and False otherwise)
If you want to make a list comprehension that operates on lists of lists, you can just nest the comprehensions:
operate :: Table -> Table
operate t = [[myFunction field|field <- row, myPredicate field]| row <- t]
myFunction :: Field -> Field
myPredicate :: Field -> Bool
Hmm, this isn't an answer since you requested using list comprehensions. But I think list comprehensions are quite ill-suited to this task. You only need take and drop.
ghci> take 2 [1,2,3,4,5]
[1,2]
ghci> drop 2 [1,2,3,4,5]
[3,4,5]
To delete an element at index i, append together the first i elements and the list with the first i+1 elements dropped.

Resources