I'm new to haskell and I want to sort list of strings. For example I have a list that is in my variable ff that contain three strings ["1 8 8 5 6", "1 4 2 3", "5 4 9 7 9 9"] and I want to sort them so my result should look like ["1 5 6 8 8", "1 2 3 4", "4 5 7 9 9 9"] Here's my code that perfectly works
import System.IO
import Control.Monad
import Data.List
import Data.Function
import Data.Array
import Data.Char
sortNumeric = sortBy (compare `on` (read :: String -> Int))
wordsWhen :: (Char -> Bool) -> String -> [String]
wordsWhen p s = case dropWhile p s of
"" -> []
s' -> w : wordsWhen p s''
where (w, s'') = break p s'
main = do
file <- readFile "test.txt"
let ff = map ((!!) (lines file)) [1,3..(length (lines file) - 1)]
let splitString = wordsWhen (==' ') (ff!!0)
let sortedResult = sortNumeric (splitString)
print sortedResult
Problem is with this line let splitString = wordsWhen (==' ') (ff!!0) I always get first element of the list, so only first element is sorted. How can I pass all values of a list? Here's what I tryied to do let splitString = wordsWhen (==' ') (ff!![0..(length(ff)-1)]) unfortunately this doesn't work. Any ideas how to solve this problem?
You can do it easily with map and a niftry trick to use words, sort and then unwords (to restore the whitespace).
Prelude> let ff=["1 8 8 5 6", "1 4 2 3", "5 4 9 7 9 9"]
Prelude> import Data.List
Prelude Data.List> map (unwords . sort . words) ff
["1 5 6 8 8","1 2 3 4","4 5 7 9 9 9"]
Edit: Improvement to correctly sort numeric values:
import Data.List
let ff=["11 8 8 5 6", "11 4 2 3", "5 4 9 7 99 9"]
let sortNumeric = (map show) . sort . (map (read :: String -> Int))
map (unwords . sortNumeric . words) ff
result:
["5 6 8 8 11","2 3 4 11","4 5 7 9 9 99"]
Related
I need to print a list of integers in Haskell in one line only separated by space...
Like , I would want to print
[6,5,4,7,3,9]
in this manner
6 5 4 7 3 9
I used the Map_ function but that prints all the elements in different lines.
You can try this
main = putStrLn . unwords . map show $ [1,2,3,4]
Instead of unwords you could also use intercalate " " for a more generic function.
You can define a customized print function, which accepts a parameter of separator:
type Separator = String
cPrint :: Show a => Separator -> a -> IO ()
cPrint sep v = putStr $ show v ++ sep
ghci> mapM_ (cPrint " ") [6,5,4,7,3,9]
6 5 4 7 3 9 ghci>
I tried to minimise the code as glennsl suggested. It turns out, I don't know how to read inputs from multiple lines in OCaml.
For example, pretend, stdin contains the following pattern
5
1 2 3 4 5
3
6 7 8
I need to read this and print to stdout. I'm using the "%d %d %d %d %d\n" format specifier as if I know the number of inputs is 5 in advance, just to illustrate my problem.
Now the following code fails with the same error Fatal error: exception End_of_file (I have tried to reproduce the same problem with fewer lines of code) if I uncomment the bottom part.
let number_of_inputs1 = read_int () in
let input_arr1 = Scanf.scanf "%d %d %d %d %d\n" (fun a b c d e -> [a]#[b]#[c]#[d]#[e]) in
let rec print_test_case inputs =
match inputs with
|[] ->(print_newline ();print_string "done test case"; print_newline ();)
|hd::tl -> (print_int hd; print_string " "; print_test_case tl)
in print_int number_of_inputs1; print_newline (); print_test_case input_arr1;
(*
let number_of_inputs2 = read_int () in
let input_arr2 = Scanf.scanf "%d %d %d\n" (fun a b c -> [a]#[b]#[c]) in
print_int number_of_inputs2; print_newline (); print_test_case input_arr2;
*)
It prints the following now,
5
1 2 3 4 5
done test case
I need to print something like
5
1 2 3 4 5
done test case
3
6 7 8
done test case
How should I read such formatted input in multiple lines from stdin correctly ?
The original problem I faced is what follows.
I have a problem where the number of test cases t is specified in the first line of the input. The t test cases follow. Each test case is comprised of two lines
line#1: number of inputs n, for this particular test case
line#2: the n input numbers separated by space
I need to do some computation for each test case. Let's assume I just need to print them back to the console with a message "done test case" after each test case output.
For example if the input was the following,
5
3
1 2 3
3
2 1 3
6
3 2 1 5 4 6
4
1 3 4 2
5
3 4 5 1 2
Observe that there are 5 test cases in this problem. The first test case for example, has 3 inputs 1 2 3, and the third one has 6, 3 2 1 5 4 6.
I need to print
1 2 3
done test case
2 1 3
done test case
3 2 1 5 4 6
done test case
1 3 4 2
done test case
3 4 5 1 2
done test case
So far, I have tried the following,
let test_cases = read_int () in (*read the number of test cases*)
let rec print_all_test_cases tc = (*define a function that will call the individual test cases*)
if (tc > 0) (*check if there are more test cases left*)
then
let num_of_inputs = read_int() in (*read the number of inputs*)
let rec read_inputs_for_test_case n arr = (*function to recursively read all inputs for the test case*)
if (n == 0)
then arr (*if everthing is read return the accumulated array*)
else
let i = Scanf.scanf "%d " (fun i -> i) in (*else read the input*)
read_inputs_for_test_case (n-1) (arr # [i]) (*recurse for the remaining inputs, accumulating current input to the argument*)
in
let rec print_test_case inputs = (*print inputs for the test case*)
match inputs with
|[] ->(print_newline ();print_string "done test case"; print_newline ();)
|hd::tl -> (print_int hd; print_string " "; print_test_case tl)
in
print_test_case (read_inputs_for_test_case num_of_inputs []); (*call to read and print inputs*)
print_all_test_cases (tc-1) (*recursively do the remaining test cases*)
else ()
in print_all_test_cases test_cases
It prints the following to stdout
1 2 3
done test case
and fails with the following error on stderr
Fatal error: exception End_of_file
How do read everything correctly and print as required ?
There is no error in your simplified code extract, uncommenting the second part should work if the stdin had the right data.
You should probably test your code with a fixed string data first:
let text = "5
1 2 3 4 5
3
6 7 8
"
let source = Scanf.Scanning.from_string text
let number_of_inputs1 = Scanf.bscanf source "%d\n" (fun n -> n)
let input_arr1 =
Scanf.bscanf source "%d %d %d %d %d\n" (fun a b c d e -> [a;b;c;d;e])
I want to get values from 2 series into one but it is not working:
I have 2 series:
a: [1 2 3]
b: [4 5 6 7]
I want to get all values in one list, so that I can access them as allv/1, allv/2... allv/7.
Following is not working since it makes a series of series and not series of values:
allv: [a b]
print allv ; => prints all 6 values, but following do not work:
print allv/1 ; => gives a (desired is 1)
print allv/2 ; => gives b (desired is 2)
print allv/3 ; => gives none (desired is 3)
I tried following function to combine values in one series:
mycombine: function [ll][
temp: []
foreach l ll [
repeat i length? l [
temp: append temp l/:i ] ]
temp]
mycombine [a b]
But above gives error:
*** Script Error: length? does not allow word! for its series argument
*** Where: length?
*** Stack: rncombine
The series has got converted into word and is not working.
How can I solve this?
Just append
a: [1 2 3]
b: [4 5 6 7]
c: [8 9 10]
d: [11 12 13 14]
>> allv: append a b
== [1 2 3 4 5 6 7]
>> a
== [1 2 3 4 5 6 7]
does what you want. But beware even a contains all values, as you have appendend the values of b to the block a. If you want a new block you have to use
allv: append copy a b
If you want to append more series you can do
>> foreach x [a b c d] [ append [] reduce x]
== [1 2 3 4 5 6 7 8 9 10 11 12 13 14]
Instead of reduce also get x is working.
Another way of combining
>> compose [(a) (b) (c)]
== [1 2 3 4 5 6 7 8 9 10 ]
I have datatype:
data SidesType = Sides Int Int Int deriving (Show)
And I need a function which get a list of SidesType and remove duplicates from it.
*Main> let a = [Sides 3 4 5,Sides 3 4 5,Sides 5 12 13,Sides 6 8 10,Sides 6 8 10,Sides 8 15 17,Sides 9 12 15,Sides 5 12 13,Sides 9 12 15,Sides 12 16 20,Sides 8 15 17,Sides 15 20 25,Sides 12 16 20,Sides 15 20 25]
*Main> removeDuplicateFromList [] a
[Sides 3 4 5,Sides 5 12 13,Sides 6 8 10,Sides 6 8 10,Sides 8 15 17,Sides 9 12 15,Sides 5 12 13,Sides 9 12 15,Sides 12 16 20,Sides 8 15 17,Sides 15 20 25,Sides 12 16 20,Sides 15 20 25]
Here is my solution:
removeElementFromList :: [SidesType] -> SidesType -> [SidesType]
removeElementFromList lst element =
let (Sides a b c) = element
in [(Sides x y z) | (Sides x y z) <- lst, (x /= a) || (y /= b)]
removeDuplicateFromList :: [SidesType] -> [SidesType] -> [SidesType]
removeDuplicateFromList inlist outlist
| (length outlist) == 0 = inlist
| otherwise =
let element = head outlist
b = tail outlist
filtered = removeElementFromList b element
in removeDuplicateFromList (inlist ++ [element]) filtered
I am just wondering if there is any other way to write this code in more haskell-way ?
As usual there is "By" function which adds flexibility:
nubBy :: (a -> a -> Bool) -> [a] -> [a]
PS Although it's O(n^2)
You're already deriving Show for your datatype. If you also derive Eq, you can use nub from module Data.List.
Use Data.List.nub
First derive the order class also:
data XYZ = XYZ .... deriving (Show, Eq, Ord)
Or write your on Eq instance:
instance Eq XYZ where
a == b = ...
Then be intelligent and use a Tree! [Computer Science Trees grow from top to bottom!][1]
import qualified Data.Map.Strict as Map
removeDuplicates ::[a] -> [a]
removeDuplicates list = map fst $ Map.toList $ Map.fromList $ map (\a -> (a,a)) list
Complexity (from right to left) for list with length N:
map of the list: O(N)
Map.fromList: O(N*log N)
Map.toList: O(log N)
map over list with list length smaller or equal to N: O(N)
They are called consecutively, this means, there are pluses between the complexities of the parts => O(2 * N + N * log N + log N) = O(N * log N)
This is way better than traversing N^2 times over the list!
See: wolframAlpha plots. I included 2*N also for comparison reasons.
2+3: http://hackage.haskell.org/package/containers-0.5.4.0/docs/Data-Map-Strict.html
[1]: Search wikipedia for Computer Science Tree
Im starting to program in Lisp and having an hard time with the Format function.
My objective is to print a list of integer sublists as N integers for line. For example:
'((1 2 3)
(4 5 6)
(7 8 9))
should be printed as
1 2 3
4 5 6
7 8 9
I tried using iteration in the format procedure, but I failed.
What I wrote was:
(format t "~{~S ~}" list)
But with this I get the sublists as "(1 2 3)" instead of "1 2 3", so i tried:
(format t "~:{ ~S ~}" list)
this time I got into the sublists but only printed the first element, so I stepped in and re-wrote the function to:
(format t "~:{ ~S ~S ~S ~}" list)
It works for sublists with 3 elements, but how can I make it work for n elements?
Thanks!
(format t "~{~%~{~A~^ ~}~}" '((1 2 3) (4 5 6) (7 8 9)))
prints
1 2 3
4 5 6
7 8 9