Merging/Combining a list of Integers with Char [Haskell] - list

I'd like a hint on how to apply this function:
dti xs = (map intToDigit (take 6 (map digitToInt xs))++['/']++map intToDigit(drop 6 (map digitToInt xs)))
on a list of Integers, e.g.; [1234567822,3245336792,...], so I'd get an output like ["123456/7822","324533/6792",...].
The point is to add a "/" after the 6th digit in each number of a list of integers, e.g.; [1234567822,3245336792,...]. Maybe there's a better way to do it than mine.

intToDigit expects a single digit, so it will raise an error on input like 1234567822.
To convert an Int (or Integer) into a list of characters, you can use show, and then split the resulting string after six digits
format n = first ++ '/':second
where
s = show n
(first,second) = splitAt 6 s
dti = map format

Related

Padding at the end of a list with a SML function

We have a list like [13,7,8,4] and a number N. We want to insert elements (some zeroes) at the end of that list with the number of N mod ListSize. Suppose that N = 6 and according to the list, ListSize is 4.
6 mod 4 = 2. So, we have to insert 2 zeroes at the end of list like [13,7,8,4,0,0].
How can we do this by a function in SML?
Padding at the end of a list is a O(n) operation. If orig is your original list and zeroes is the zeroes you're padding, orig # zeroes involves prepending every single element of orig to zeroes.
The compositional approach would be to first find the number of zeroes, then create those zeroes, and then append them.
fun numberOfZeroes xs n = n mod List.length xs
fun replicate x 0 = []
| replicate x n = x :: replicate x (n-1)
fun zeroes xs n = replicate 0 (numberOfZeroes xs n)
fun pad xs n = xs # zeroes xs n
You could save one traversal by counting the length of xs at the same time as you are appending the zeroes (unlike separate length/#). A combined function might look like this:
fun pad xs n =
let fun pad' (x::xs) count = x :: pad' xs (count + 1)
| pad' [] count = replicate 0 (count mod n)
in pad' xs 0 end
This function, however, isn't tail-recursive, so for large xs it might run out of stack space. (replicate isn't either, but will only produce lists of length N.) To make it tail-recursive, one way or the other, one must traverse the list twice. Also, building complex functions out of less complex functions decreases cognitive load.
Lastly, your description of the problem was very fine. The next time you have a similarly clear description of a problem, try and write a test that a correct implementation will pass. E.g. the test you described was:
val test1 = pad [13,7,8,4] 6 = [13,7,8,4,0,0]
Besides one test, add more until you've defined all the corner cases. For example:
val test2 = pad [13,7,8,4] 4 = ?

Efficient list operations?

I have the following function that searches through [Char] and returns [Char] based on their index number:
myList = "abcdefghijk"
searchText = foldl (\acc el -> if elemIndex el myList > Just 11 then el : acc else acc) [] myList
Clearly this is somewhat inefficent as elemIndex returns the index number of each element then applies the condition.
Is there a more efficient way of performing this operation?
The usual approach is to pair each character with its index before doing the real processing
process $ zip [0..] myList
Now process can perform the actual computation, which can use the indexes as well as the characters.
In some contexts, this approach is known as the Schwartzian transform.
Your function returns a string that skips the first twelve characters and reverses the output, dropping any characters that are also in those first twelve.
For a more efficient version of this, you could use Data.Set to store those first twelve characters for fast lookup, the filter them out and reverse the remainder of the string:
import qualified Data.Set as Set
searchText =
let hash = (Set.fromList . take 12) myList
in (reverse . filter (flip Set.notMember hash) . drop 12) myList

SML: find maximal element in a given column of a list

I need to find a greatest element in the given COLUMN of the list:
myList = [(1,2,0), (3,5,8), (9,1,2)]
Something like this:
max(myList(:,2)) // maximal element in the 2nd column
In this example the answer should be 5.
I wrote the following code, but how can I put the 1st or 2nd column into the input of "max"?
fun findSum(myList:MyList) = max(#1 myList) + max(#2 myList)
fun max [] = 0
| max (x::xs) = foldl Int.max x xs
Thanks.
The simplest way would be to map the appropriate selector onto the list, then using max on the result of that.
max (map #2 myList)
Note, of course, there's no way to do it for tuples of arbitrary size (due to types), and no easy way to convert an integer into a selector. (Apart from creating a function where you manually map each integer onto the appropriate selector.)

Haskell List of Int : [123] to [1,2,3]

Problem
i have list of int as [123,123] which i required to be as [1,2,3,1,2,3]
Current Code
i tried out the following code using recursion
fat::[Int]->[Int]
fat [] = []
fat (a,b,c:xs) = a : b : c : fat xs
Conclusions
i have no idea how to acess values as '1' , '2 , '3 in a list [123,123] separetly
I suggest to use the digs function given in this answer on each element of your list. It splits an Int into a list of digits ([Int]). Then you just need to concatenate the resulting lists. This 'map and concatenate results' requirement is a perfect job for concatMap
fat :: [Int] -> [Int]
fat = concatMap digs
This gives:
*Main> fat [123,123]
[1,2,3,1,2,3]
Which is what you want, if I understood correctly.
splitNum :: Int -> [Int]
splitNum n | n <= 9 = [n]
| otherwise = (splitNum (n `div` 10)) ++ [n `mod` 10]
fat :: [Int] -> [Int]
fat x = concatMap splitNum x
splitNum is used to convert an Int to a [Int] by splitting it into the division by ten reminders and appending the resulting Int to the splitted rest (recursion!)
Now, having a function that converts numbers into lists, go through input, apply splitNum to any Number in the inner list and concat all resulting lists (list comprehension!)
As a new Haskell programmer I will give you my thoughts of this problem. Just because I think it's good to have many alternatives, especially from different people with different experience.
Here's my take on the problem:
For each item in the list, convert that item to a char list using read.
Send that char list into a function which converts each item of that list into an int, then return an list of ints.
Concat that list of ints into the main list.
To clarify:
[123, 234]
123 turns into ['1', '2', '3']
['1', '2', '3'] turns into [1, 2, 3]
[1, 2, 3] gets concat in the main list
the cycle repeats for 234.
The util function would look something like this:
import Char
charsToInts :: [Char] -> [Int]
charsToInts [] = []
charsToInts (x:xs) = digitToInt x : charsToInts xs
Coming from a imperative background that's how I would have solved it. Probably slower than just splitting the number mathematically, but I thought it would be interesting to show a alternative.
To pinpoint the problem bluntly, you have no idea how to access the digits separately because you do not understand Haskell types and pattern matching. Let me try to help dispel some of your misconceptions.
Let's look at your list:
[123, 123]
What is its type? It is clearly a list of ints, or [Int]. With lists, you can pattern match on the constructor :, known to lispers as "cons", or "list constructor". You put a single element on the left side of the :, and another list on the right side. The list on the right side can be the empty list [], which basically indicates the end of the list. Haskell provides "syntactic sugar" to make lists easier to write, but [123,456] actually gets desugared into 123:(456:[]). So when you pattern match (x:y:z), you can now see that x will be assigned 123 and y will be assigned 456. z will be the rest of the list after x and y; in this case only [] is left.
Now then, pattern matching with : works for lists. Ints are not lists, so you can't use : to pattern match on the digits of an Int. However, Strings are lists, because String is the same as [Char]. So if you turn your Int into a String then you can pattern match on each character.
map show [123, 123]
map applies a function to all elements of a list. show can take an Int and turn it into a String. So we map show over the list of Ints to get a list of Strings.
["123", "123"]
Now let's turn those Strings into lists of Ints. Since String is simply [Char], we will again make use of map.
map digitToInt "123" -- this requires that you import Data.Char (digitToInt)
This will give us [1,2,3]; each Char in the list is turned into an Int. This is what we want to do to each String in our list ["123", "123"]. We want to map digitToInt to each String. But we have a list of Strings. So what do we do? We map it!
map (map digitToInt) ["123", "123"]
This will give us [[1,2,3], [1,2,3]]. Almost what we wanted. Now we just have to flatten the list of list of Ints ([[Int]]) into just a list of Int ([Int]). How can we do that? Stop...Hoogle time! Hoogling [[a]] -> [a] we find the very first hit, concat, is exactly what we wanted.
Let's put it all together. First we do map show to get from [Int] to [String]. Then we do map (map digitToInt) to get from [String] to [[Int]]. Then we do concat to get from [[Int]] to [Int]. Then we'll just print it out!
import Data.Char (digitToInt)
main = print $ concat $ map (map digitToInt) $ map show $ [123, 123]
Now let's pull most of that out into a function fat
import Data.Char (digitToInt)
main = print $ fat [123, 123]
fat :: [Int] -> [Int]
fat xs = concat $ map (map digitToInt) $ map show $ xs
From here you could make it prettier in a few different ways. concat $ map is the same as concatMap, and since we map both (map digitToInt) and show in sequence, we can merge those. Also making it pointfree, we can end up with quite a terse definition:
fat = concatMap (map digitToInt . show)
For the sake of completeness, I wrote it as suggested by #Ancide
Implementation
fat' :: [Int] -> [Int]
fat' l = map (read) [[z] | z <- [x | k <- (map (show) l), x <- k]]
Explanation:
{- last result -} stands for the result of the last code explained.
map (show) l
This takes every element inside l and converts it to [String].
[x | k <- {- last result -}, x <- k]
While k goes through all elements inside the last result, x enumerates all character in each k. All those are added to a list. Now you have a String, respectively a [Char] with all digits next to each others.
[[z] | z <- {- last result -}]
This part takes each Char from the String and puts it into an empty String. Notice the [z] part! This make a list around z, which is (see above) the same as String. Now you have a list of String with a String for each digit.
map (read) {- last result -}
This takes every item in the last result and converts it back to Int and joins them to [Int]. Now you have a list of type [Int] of the wanted result.
Resumé
Although this implementation is possible, it's neither fast, due to all the type conversions, nor readable.
Playing around with the list monad I came up with this. Pretty much the same #Ankur's solution, except using the list monad:
fat :: [Int] -> [Int]
fat is = is >>= show >>= return . digitToInt
If you had two numbers, a and b then you could turn them into a single number by doing 10*a + b. The same principles apply for three.
It sounds like one way of doing this would be to splitEvery into lumps of three and then map a function to turn a list of three into a single number.
Does that help?
You need a function to convert Integer to string... which is obviously Show function
Another function to convert a Char to Integer which is "digitToInt" in module Char
And here we go :
fat::[Int]->[Int]
fat [] = []
fat ls = concat $ map (map digitToInt) (map show ls)
Please let me know if it works :)

Convert list of Integers into one Int (like concat) in haskell

Pretty much what the title says. I have a list of Integers like so: [1,2,3]. I want to change this in to the Integer 123. My first thought was concat but that doesn't work because it's of the wrong type, I've tried various things but usually I just end up returning the same list. Any help greatly appreciated.
Also I have found a way to print the right thing (putStr) except I want the type to be Integer and putStr doesn't do that.
You can use foldl to combine all the elements of a list:
fromDigits = foldl addDigit 0
where addDigit num d = 10*num + d
The addDigit function is called by foldl to add the digits, one after another, starting from the leftmost one.
*Main> fromDigits [1,2,3]
123
Edit:
foldl walks through the list from left to right, adding the elements to accumulate some value.
The second argument of foldl, 0 in this case, is the starting value of the process. In the first step, that starting value is combined with 1, the first element of the list, by calling addDigit 0 1. This results in 10*0+1 = 1. In the next step this 1 is combined with the second element of the list, by addDigit 1 2, giving 10*1+2 = 12. Then this is combined with the third element of the list, by addDigit 12 3, resulting in 10*12+3 = 123.
So pointlessly multiplying by zero is just the first step, in the following steps the multiplication is actually needed to add the new digits "to the end" of the number getting accumulated.
You could concat the string representations of the numbers, and then read them back, like so:
joiner :: [Integer] -> Integer
joiner = read . concatMap show
This worked pretty well for me.
read (concat (map show (x:xs))) :: Int
How function reads:
Step 1 - convert each int in the list to a string
(map show (x:xs))
Step 2 - combine each of those strings together
(concat (step 1))
Step 3 - read the string as the type of int
read (step 2) :: Int
Use read and also intToDigit:
joinInt :: [Int] -> Int
joinInt l = read $ map intToDigit l
Has the advantage (or disadvantage) of puking on multi-digit numbers.
Another idea would be to say: the last digit counts for 1, the next-to last counts for 10, the digit before that counts for 100, etcetera. So to convert a list of digits to a number, you need to reverse it (in order to start at the back), multiply the digits together with the corresponding powers of ten, and add the result together.
To reverse a list, use reverse, to get the powers of ten you can use iterate (*10) 1 (try it in GHCi or Hugs!), to multiply corresponding digits of two lists use zipWith (*) and to add everything together, use sum - it really helps to know a few library functions! Putting the bits together, you get
fromDigits xs = sum (zipWith (*) (reverse xs) (iterate (*10) 1))
Example of evaluation:
fromDigits [1,2,3,4]
==> sum (zipWith (*) (reverse [1,2,3,4]) [1,10,100,1000, ....]
==> sum (zipWith (*) [4,3,2,1] [1,10,100,1000, ....])
==> sum [4 * 1, 3 * 10, 2 * 100, 1 * 1000]
==> 4 + 30 + 200 + 1000
==> 1234
However, this solution is slower than the ones with foldl, due to the call to reverse and since you're building up those powers of ten only to use them directly again. On the plus side, this way of building numbers is closer to the way people usually think (at least I do!), while the foldl-solutions in essence use Horner's rule.
join :: Integral a => [a] -> a
join [x] = x
join (x:xs) = (x * (10 ^ long)) + join(xs)
where long = length(x:xs)
We can define the function called join, that given a list of Integral numbers it can return another Integral number. We are using recursion to separate the head of the given list with the rest of the list and we use pattern matching to define an edge condition so that the recursion can end.
As for how to print the number, instead of
putStr n
just try
putStr (show n)
The reasoning is that putStr can only print strings. So you need to convert the number to a string before passing it in.
You may also want to try the print function from Prelude. This one can print anything that is "showable" (any instance of class Show), not only Strings. But be aware that print n corresponds (roughly) to putStrLn (show n), not putStr (show n).
I'm no expert in Haskell, but this is the easiest way I can think of for a solution to this problem that doesn't involve using any other external functions.
concatDigits :: [Int] -> Int
concatDigits [] = 0
concatDigits xs = concatReversed (reverseDigits xs) 1
reverseDigits :: [Int] -> [Int]
reverseDigits [] = []
reverseDigits (x:xs) = (reverseDigits xs) ++ [x]
concatReversed :: [Int] -> Int -> Int
concatReversed [] d = 0
concatReversed (x:xs) d = (x*d) + concatReversed xs (d*10)
As you can see, I've assumed you're trying to concat a list of digits. If by any chance this is not your case, I'm pretty sure this won't work. :(
In my solution, first of all I've defined a function called reverseDigits, which reverses the original list. For example [1,2,3] to [3,2,1]
After that, I use a concatReversed function which takes a list of digits and number d, which is the result of ten power the first digit on the list position. If the list is empty it returns 0, and if not, it returns the first digit on the list times d, plus the call to concatReversed passing the rest of the list and d times 10.
Hope the code speaks for itself, because I think my poor English explanation wasn't very helpful.
Edit
After a long time, I see my solution is very messy, as it requires reversing the list in order to be able to multiply each digit by 10 power the index of the digit in the list, from right to left. Now knowing tuples, I see that a much better approach is to have a function that receives both the accumulated converted part, and the remainder of the list, so in each invocation in multiplies the accumulated part by 10, and then adds the current digit.
concatDigits :: [Int] -> Int
concatDigits xs = aggregate (xs, 0)
where aggregate :: ([Int], Int) -> Int
aggregate ([], acc) = acc
aggregate (x:xs, acc) = aggregate (xs, (acc * 10 + x))