Haskell int list to String - list

I would like to know if there is a simple way to turn [5,2,10] into "52a".
Where its not just to this case, I want to associate any number >9 with the corresponding letter.
Thanks in advance.

You want to do something to each element of a list in order to get a new list. In other words, you want to apply a function (that you will have to define yourself) to each element. This is what the map function from the Prelude is for.
To convert between integers and individual characters, you could use the chr and ord functions from the Data.Char module.
So,
map (\i -> if i < 10 then chr (i + ord '0') else chr (i - 10 + ord 'a'))
is a function of type [Int] -> String that does what you want (no error checking included, though).

Slower but more elegant:
f = map ((['0'..'9'] ++ ['a'..'z']) !!)
If your numbers are 0-15 use map intToDigit from Data.Char.

Related

What is the idiomatic Haskell way to check if one list contains all the values in another list?

My question is similar to How can i use haskell to check if a list contains the values in a tuple, but in my case, the list with values which must all be in my original list is the alphabet. It feels really messy to have 26 calls to elem, all ANDed together.
Is there any more concise way to check if a given list contains all of the elements in another list, where the other list is 26 items long?
I like the answer by user1984, but it does leave implicit a bit the way you would handle non-alphabetic characters. Here's one that's almost as simple, but doesn't need extra code to handle non-alphabetic characters. The basic idea is to go the other direction; their answer builds up a set, this one tears one down by deleting one character at a time. It is also O(n), like theirs.
import qualified Data.Set as S
isPangram :: String -> Bool
isPangram = S.null . foldr S.delete (S.fromList ['a'..'z'])
If you want case insensitivity, you can import Data.Char and change S.delete to (S.delete . toLower).
This is based on Daniel Wagner's answer, but it finishes early if all the letters are found, whereas his walks the whole list, then works backwards deleting elements, then gives an answer when it gets back to the beginning.
import qualified Data.Set as S
import Data.Set (Set)
letters :: Set Char
letters = S.fromList ['a'..'z']
isPangram :: String -> Bool
isPangram xs0 = go xs0 letters
where
go :: String -> Set Char -> Bool
go [] letters = S.null letters
go (c : cs) letters =
S.null letters || go cs (S.delete c letters)
You may be wondering why I match on the string first and check on letters under the match, instead of the other way around. Well, that's only because it's fun to rewrite this using foldr:
isPangram :: String -> Bool
isPangram xs0 = foldr step S.null xs0 letters
where
step :: String -> Set Char -> Bool
step c r letters =
S.null letters || r (S.delete c letters)
For something like the alphabet, Data.Set is not actually the most efficient way. It's better to use something like IntSet, which is much more compact and significantly faster.
import qualified Data.IntSet as S
import Data.IntSet (IntSet)
letters :: IntSet
letters = S.fromList (map fromEnum ['a'..'z'])
isPangram :: String -> Bool
isPangram xs0 = foldr step S.null xs0 letters
where
step :: String -> IntSet -> Bool
step c r letters =
S.null letters || r (S.delete (fromEnum c) letters)
My understanding is that you are trying to check whether a string is a pangram, meaning it contains all the [insert your preferred language] alphabet.
The following code uses Data.Set. A set data structure can't contain duplicate elements by definition. We use this property of a set to count the number of elements that are in it after we added all the character from the string to it. If it's equal to the number of the alphabet we are working with, it means that the string contains all the characters of the alphabet, so it's a pangram.
Note that this code does not take care of the difference between lower and upper case letters and also counts white space and punctuation. This would give you wrong answers if there are any of these cases. With some tweaking you can make it work though.
The time complexity of this solution is n * log 26 which is just n in Big O, as Daniel Wagner pointed out. The reason is that while Haskell's default set is a balanced tree, the number of elements in the set never goes above 26, so it becomes linear. Using a hashing implementation of the set may result in some optimization for very large strings. The space complexity is constant since the additional space we are using never exceeds 26 characters.
import qualified Data.Set as S
isPangram :: [Char] -> Bool
isPangram s = length (S.fromList s) == 26
To answer your question literally,
allPresent :: Eq a => [a] -> [a] -> Bool
allPresent alphabet xs = foldr (\a r -> elem a xs && r) True alphabet
is a concise and inefficient code that will call elem as many times as there are letters in your alphabet and will "AND" the results.
For example, for a three-letter alphabet a, b, and c, it will be equivalent to an &&-chain of three calls to elem and a True:
allPresent [a, b, c] xs
==
elem a xs && elem b xs && elem c xs && True
It will stop as soon as the first missing letter will be detected, returning False. But it will potentially comb through the whole of xs anew for each letter of the alphabet, which is inefficient.
If you are infact looking for a pangram, you could try this solution which I came up with.
import Data.Char ( toLower )
isPangram :: String -> Bool
isPangram text = all isInText ['a'..'z'] where
isInText x = x `elem` map toLower text

Haskell list length alternative

Hi I've got a list on Haskell with close to 10^15 Int's in it and I'm trying print the length of the list.
let list1 = [1..1000000000000000] -- this is just a dummy list I dont
print list1 length -- know the actual number of elements
printing this takes a very long time to do, is there another way to get the number of elements in the list and print that number?
I've occasionally gotten some value out of lists that carry their length. The poor man's version goes like this:
import Data.Monoid
type ListLength a = (Sum Integer, [a])
singletonLL :: a -> ListLength a
singletonLL x = (1, [x])
lengthLL :: ListLength a -> Integer
lengthLL (Sum len, _) = len
The Monoid instance that comes for free gives you empty lists, concatenation, and a fromList-alike. Other standard Prelude functions that operate on lists like map, take, drop aren't too hard to mimic, though you'll need to skip the ones like cycle and repeat that produce infinite lists, and filter and the like are a bit expensive. For your question, you would also want analogs of the Enum methods; e.g. perhaps something like:
enumFromToLL :: Integral a => a -> a -> ListLength a
enumFromToLL lo hi = (fromIntegral hi-fromIntegral lo+1, [lo..hi])
Then, in ghci, your example is instant:
> lengthLL (enumFromToLL 1 1000000000000000)
1000000000000000

Getting elements from a list by an index list

I have two lists in Haskell.
Original list containing string values:
["Hello", "HELLO", "", "WORLD", "xxx", "world"]
Index list containing integer values where the strings are all upper case in the original list:
[1,3]
I incremented all the values in the index list with a function I created and make index2 list, overall it looks like this:
My code:
import Data.List
import Data.Char
import Data.Maybe
main = do
contents <- readFile "h.txt"
let original = lines (contents)
let allUpper = lines (map toUpper contents)
let onlyUpper = filter(/="") (intersect original allUpper)
let upperIndex = findIndices ('elem' onlyUpper) original
let index2 = (map increment upperIndex)
print index2
increment :: Int -> Int
increment x = x+1
I have managed to came this far with the help of yours. However, since I am a beginner I do not seem to understand how iteration over lists works.
The thing I want to accomplish is to check whether the corresponding index values (in index2) are empty or not in the original list, if they are empty, I want to remove them in index2.
Filtering empty elements
The thing I want to accomplish is to check whether the corresponding
index values (in index2) are empty or not in the original list, if
they are empty, I want to remove them in index2.
The code already filters out empty elements! Look at the following line:
let onlyUpper = filter(/="") (intersect original allUpper)
This line does two things:
it keeps only elements which are constituted only with uppercase letters(intersect original allUpper),
it filters out empty elements (filter(/="")).
If by empty elements you mean strings which contains only space characters or nothing, you can use instead:
filter (all isSpace)
Iterating over lists
I do not seem to understand how iteration over lists works.
In Haskell, lists are single chained lists: each element contains a value and a reference to the next value.
Therefore lists are not indexed: the !! operator have to go through each element to access a specific element making lists completely inefficient when dealing with direct access.
When you’re submitting a list to a function, you simply give it the first element.
With these considerations, when you work on lists, you have to avoid accessing elements via their index.
The idea is to create functions which do their job on simple values and mapping them to list of elements. Take a look at the toUpper function:
toUpper :: Char -> Char
It takes a Char and returns its uppercased version (also a Char).
Haskell does not have a toUpper function which works on String, you have to use something like map or <$> to apply toUpper to a list of char (a String):
map toUpper "ab" -- "AB"
toUpper <$> "ab" -- "AB"
The idea is to have functions which does only one specific thing. Upercasing and iterating over a list are two different things. Does the toUpper function need to know the index of the element it will uppercase? No!
Iterating over a list with index
You may ask: but what if my function REALLY need to consider the index of the elements? (ie: for filtering out even or odd elements).
You have two way of considering it:
a List is not the type you need to work with. Maybe Data.Map, Data.IntMap or Data.Vector are better suited for the task (see these modules for more information),
you need to use an intermediate type which will hold the index.
For example:
let string = "abcde"
let indexedString = zip [1..] string
print indexedString -- [(1, 'a'), (2, 'b), (3, 'c), (4, 'd), (5, 'e)]
Note that this also solves your need of an increment function since the index is started at whatever value you want.
To go back to the original string, you write:
map snd indexedString -- "abcde"
You need to use the fst and snd functions to work with the intermediate type, or to use pattern matching:
filter (\x -> snd x == 'b') indexedString -- [(2, 'b')]
map (\(i,s) -> (i, toUpper s)) indexedString -- [(1,'A'),(2,'B'),(3,'C'),(4,'D'),(5,'E')]
Taking the index into account:
let string = "abcde"
indexedString = zip [1..] string
upperEven (i, c) | even i = (i, toUpper c)
| otherwise = (i, c)
print $ map upperEven indexedString -- [(1,'a'),(2,'B'),(3,'c'),(4,'D'),(5,'e')]
print $ map snd $ map upperEven indexedString -- "aBcDe"
Notes
The increment function already exists in Haskell, it’s called succ (it is also a more generic function which works on every types supporting the Enum class like Int, Char…)
Why not use words :: String -> [String] on the contents you get from a file? Using lines :: String -> [String] would be an alternative if you had one word per line.
Then if i get your problem right, you could write the following to solve your problem:
import Data.List (findIndices)
import Data.Char (isUpper)
allUpperOneBasedIndices :: String -> [Int]
allUpperOneBasedIndices = map succ . findIndices (all isUpper) . words

How to use a tuple's elements as indexes to reach a list's elements-haskell

I have a list of tuples, which I am trying to use its elements to reach a nested list's elements.
list = [["c","a","b"],["k","l","m"]]
indexTuple = [(0,1),(1,1),(1,2)]
this way I need to check whether there is an "a" in one of the elements of the list corresponding to my indexTuple's elements. My attempt so far;
seekinga :: [[[Char]]] -> Int -> Int -> Int -> [(Int,Int)]
seekinga list x y width
| list !!(map fst indexTuple) !!(map snd indexTuple) == "a" = [(fst indexTuple,snd indexTuple)]
| otherwise = [()]
where indexTuple = [(x,y) | x <- [x-width..x+width], y <- [y-width..y+width]]
this obviously does not work, because the !! operator wants integers to work on, but map returns lists. Any suggestions are very much appreciated.
You really have two separate concerns: given two numbers, how do you index into a nest list and how do you get two numbers out of a tuple.
The first problem is easy to solve just by looking at types. You know how to index into one list: (!!) :: [a] -> Int -> a. Here, a can be anything, including a nested list. So, given [[[Char]]], we can use !! to get a [[Char]]. And, since this is a list itself, we can use !! again to get a [Char]. ([Char] is just String, in case you don't realize.)
So all we need to do here is use !! then use it again on the result of the first one.
Now, how do we actually get the two numbers out? This is where we use pattern matching. We can just match against a tuple with a let statement:
let (i, j) = tuple in ...
Now just put the two together and you're set.
So you can view an element with:
> list !! 1 !! 2
"m"
So lets make this a function:
:set -XNoMonomorphismRestriction
> let index lst i j= lst !! i !! j
And lets filter out those indexs which do not point to "a"
> filter (\(i, j) -> index list i j == "a") indexTuple
[(0,1)]
If instead
list = [["c","a","b"],["k","l","a"]]
then
> filter (\(i, j) -> index list i j == "a") indexTuple
[(0,1),(1,2)]
Using !! may not be your best option however, in fact it probably is not. I tried to break out the two parts of the problem, as I understood it, access the element and filter for indexes.

What to use instead of a list comprehension

I'm just getting started with Haskell and finished a nice exercise to make a Caesar cipher.
One of the first steps was to make a function that will take a letter and turn it into a number. I know that chr and ord can do this already but part of the exercise was to write your own.
let2num c = head [ b | (a,b) <- zip ['a'..'z'] [0..25], a==c]
I'm new to the Haskell syntax and one of the first things I learned was list comprehensions, so that has become my hammer. I'm very curious though, what is another (likely better) way to write this function?
If you're curious the rest of the cipher is in a gist.
EDIT
I'm also interested in other ways to translate back from numbers to letters.
num2let d = head [ a | (a,b) <- zip ['a'..'z'] [0..25], b==(d `mod` 26)]
My solution:
import Data.List
let2num c = let (Just n) = elemIndex c ['a'..'z'] in n
Or:
import Data.List
import Data.Maybe
let2num c = fromJust $ elemIndex c ['a'..'z']
Or in pointless style:
import Data.List
import Data.Maybe
let2num = fromJust . (flip elemIndex) ['a'..'z']
The function elemIndex returns the index of the first element in the given list which is equal (by ==) to the query element, or Nothing if there is no such element.
The Maybe type encapsulates an optional value. A value of type Maybe a either contains a value of type a (represented as Just a), or it is empty (represented as Nothing). Using Maybe is a good way to deal with errors or exceptional cases without resorting to drastic measures such as error.
The function fromJust extracts the element out of a Just.
The reverse process:
num2let = (!!) ['a'..'z']
!! is a List index (subscript) operator, starting from 0. It is an instance of the more general Data.List.genericIndex, which takes an index of any integral type.
(!!) is partially applied here, which means it still needs one argument of type Int to yield the result (a value from the list whose index equals to Int value you pass to num2let).
“Caesar simply replaced each letter in the message by the letter three places further down the alphabet, wrapping around at the end of the alphabet.” We can simply write it in Haskell. In fact we can avoid let2num and num2let altogether.
So let's start with defining a table to map plain text alphabet to the cipher text alphabet:
cipher = let abc = ['a'..'z']
code = drop 3 abc ++ take 3 abc
in zip abc code
It will look like
[('a','d'),('b','e'),('c','f'),('d','g'), ... ]
Now we can encrypt a symbol, if we simply lookup the letter in this dictionary:
ghci> lookup 'a' cipher
Just 'd'
lookup returns a Maybe Char value, we need to convert it to simply a Char, and for this I use maybe function, using '?' for symbols which were not found in the cipher, and id (identity function = no changes) to found symbols:
ghci> maybe '?' id (lookup 'a' cipher)
'd'
Now we can write an encrypt function to encode just one symbol, it will leave missing characters, like a space, unencrypted:
encrypt c = maybe c id (lookup c cipher)
To encrypt an entire string:
ghci> map encrypt "haskell is fun"
"kdvnhoo lv ixq"
So we can put it all together:
encrypt c = maybe c id (lookup c cipher)
where
cipher = let abc = ['a'..'z']
code = drop 3 abc ++ take 3 abc
in zip abc code
For completeness, I think somebody should mention that list comprehensions are just a shortcut for writing stuff in the list monad. Your code transcribed is, roughly, this:
let2num c = head $ do (a,b) <- zip ['a'..'z'] [0..25]
if a == c then [b] else []
Not a very interesting example, but there you go.
Also, de-sugaring the do syntax, this is the same:
let2num c = head $ zip ['a'..'z'] [0..25] >>= \(a,b) -> if a == c then [b] else []
I'm not sure why you are opposed to the ord solution. List-based solutions perform unnecessary work (traversing a list). And they still are desugared into invocation of the enumFromTo, a method of the Enum class which allows to convert between Ints and Chars in the same way as ord/chr do. This is the lowest-level interface provided for Char type, so you hardly can "write your own" here (apart from doing boxing/unboxing yourself, but this is not a big joy).
I would go with the following:
import Data.Char
caesar :: Int -> Char -> Char
caesar n c = if isAlpha c
then chr (ord 'a' + (ord c - ord 'a' + n) `mod` 26)
else c
and map (caesar n) over the string with n the desired offset.