I have this code, which in my opinion is too long. And I was wondering if there's a way for me to simplify or shorten it.
I have this helper-function swap which takes in two lists of integers and returns them after swapping a number from on to the other All lists have 5 ints in them, so I fill in with zeroes if there are less than that.
It looks like this:
-- Takes in two lists and moves one non-zero int from one to the other
swap :: [Int] -> [Int] -> [[Int]]
swap xs ys
| xs == ys = [xs, ys] -- If both lists are all zeroes
| all (==0) ys = -- If the second list is all zeroes
let
e = head $ filter (/= 0) xs -- First non-zero element from first list
newX = replicate (length xs - length (filter (/= 0) xs) - 1) 0 ++ tail (filter (/= 0) xs)
newY = tail ys ++ [e]
in
[newX, newY]
| otherwise =
let
e = head $ filter (/= 0) xs -- First non-zero element from first list
newX = replicate (length xs - length (filter (/= 0) xs) + 1) 0 ++ tail (filter (/= 0) xs)
newY = replicate (length (filter (==0) ys) - 1) 0 ++ [e] ++ drop (length xs - length (filter (/= 0) ys)) ys
in
[newX, newY]
I am using it in my function below, which is the function I feel like is too long:
move :: Int -> Int -> [[Int]] -> [[Int]]
move a b ints
| a == b = error "a and b cannot be the same integer"
| a == 1 && b == 2 =
let
fst = ints !! (a-1)
snd = ints !! (b-1)
swapped = swap fst snd
in
[head swapped, last swapped, last ints]
| a == 1 && b == 3 =
let
fst = ints !! (a-1)
snd = ints !! (b-1)
swapped = swap fst snd
in
[head swapped, ints !! 1, last swapped]
| a == 2 && b == 1 =
let
fst = ints !! (a-1)
snd = ints !! (b-1)
swapped = swap fst snd
in
[last swapped, head swapped, last ints]
| a == 2 && b == 3 =
let
fst = ints !! (a-1)
snd = ints !! (b-1)
swapped = swap fst snd
in
[head ints, head swapped, last swapped]
| a == 3 && b == 1 =
let
fst = ints !! (a-1)
snd = ints !! (b-1)
swapped = swap fst snd
in
[last swapped, ints !! 1, head swapped]
| a == 3 && b == 2 =
let
fst = ints !! (a-1)
snd = ints !! (b-1)
swapped = swap fst snd
in
[head ints, last swapped, head swapped]
| otherwise = error "a and b must be either 1, 2 or 3"
This function takes in two ints and a list consisting of 3 lists of ints, where each list has 5 integers, so a sample input would be f.ex
[[1,2,3,4,5],[0,0,0,0,0],[0,0,0,0,0]] or
[[0,0,0,4,5],[0,0,0,2,3],[0,0,0,0,1]] or
[[0,0,3,4,5],[0,0,0,0,1],[0,0,0,0,2]]
So $a$ and $b$ can only be either 1,2, or 3. Giving me $2^3=6$ different cases to consder. Even If manage to get it down to two cases $a>b$ and $b>a$ I still get too many lines of code compared to what I expect is proper for Haskell. Is there any way of shortening this code?
This is not a full answer yet, but the start of one. Look how I removed all code duplication into where blocks. There are still plenty of opportunities of simplification.
-- Takes in two lists and moves one non-zero int from one to the other
swap :: [Int] -> [Int] -> [[Int]]
swap xs ys
| xs == ys = [xs, ys] -- If both lists are all zeroes
| all (==0) ys = -- If the second list is all zeroes
let
newX = replicate (length xs - length nonZeroXs - 1) 0 ++ tail nonZeroXs
newY = tail ys ++ [e]
in
[newX, newY]
| otherwise =
let
newX = replicate (length xs - length nonZeroXs + 1) 0 ++ tail nonZeroXs
newY = replicate (length (filter (==0) ys) - 1) 0 ++ [e] ++ drop (length xs - length (filter (/= 0) ys)) ys
in
[newX, newY]
where
nonZeroXs = filter (/= 0) xs
e = head $ filter (/= 0) xs -- First non-zero element from first list
The only difference between newXs is the signal of the the final addition. Which suggests that the entire decision block might be not be at it's best place.
move :: Int -> Int -> [[Int]] -> [[Int]]
move a b ints
| a == b = error "a and b cannot be the same integer"
| a == 1 && b == 2 = [head swapped, last swapped, last ints]
| a == 1 && b == 3 = [head swapped, ints !! 1, last swapped]
| a == 2 && b == 1 = [last swapped, head swapped, last ints]
| a == 2 && b == 3 = [head ints, head swapped, last swapped]
| a == 3 && b == 1 = [last swapped, ints !! 1, head swapped]
| a == 3 && b == 2 = [head ints, last swapped, head swapped]
| otherwise = error "a and b must be either 1, 2 or 3"
where
fst = ints !! (a-1)
snd = ints !! (b-1)
swapped = swap fst snd
Have a good look on the above and run some tests. I don't have the time to test it myself right now.
Related
I have a function which returns a list of halves of palindromes found from the input list. It works if I use an if-statement on one row but I'd like to use guards. Guards give me a parse error. I read many cases giving this kind of error, but I didn't figure out my case. Here is the code:
palindromeHalfs :: [String] -> [String]
palindromeHalfs xs = map firstHalf (filter palindrome xs)
where
firstHalf :: String -> String
firstHalf ys | (length ys) `rem` 2 == 0 = take ((div (length ys 2)) ys
| otherwise = take ((div (length ys 2) + 1) ys
palindrome :: String -> Bool
palindrome str | str == reverse str = True
| otherwise = False
And the error:
palindromeHalfs.hs:6:20: error: parse error on input `otherwise'
|
6 | | otherwise = take ((div (length ys 2) + 1) ys
| ^^^^^^^^^
The function works if I replace
firstHalf ys | (length ys) `rem` 2 == 0 = take ((div (length ys 2)) ys
| otherwise = take ((div (length ys 2) + 1) ys
with
firstHalf ys = if (length (ys !! 0)) `rem` 2 == 0 then take ((div (length (ys !! 0)) 2)) ys
else take ((div (length (ys !! 0)) 2) + 1) ys
In my code the if-statement is one row, it didn't fit here. I'd appreciate if someone can tell me which is preferred, if or guards. And of course, why my guards do not work.
The parentheses are not balanced in
take ((div (length ys 2)) ys
As for style, guards are much preferred over if/else in cases where either may be used. Note also that even :: Integral a => a -> Bool is a function that exists; you don't have to invent it with rem.
I want to reorder a list in the following way:
[5,6,7,8,9] -> [7,5,9,6,8]
[6,7,8,5,4,3] -> [8,5,6,3,7,4]
It's supposed to get the middle number or numbers of the list and put them in the starting position. After that it should start to get the two outer numbers of the list and add them in and work its way in.
I have the following code to get the middle numbers and put them into the beginning of the list but can't figure out how to start adding the outer numbers into the new list.
-- import Data.List
-- import System.IO
longitude xs = length xs
middle xs = length xs `div` 2
addOne xs = middle xs - 1
oneMore xs = length xs - 1
otherCase xs = oneMore xs `div` 2
valuea xs = xs !! middle xs
valueb xs = xs !! addOne xs
valuec xs = xs !! otherCase xs
modulus xs = longitude xs `mod` 2
order xs = midNums xs
takes xs = take (otherCase xs) xs
oddOne xs = otherCase xs + 1
takeX xs = drop (oddOne xs) xs
value xs = takes xs ++ takeX xs
reorder xs = drop (otherCase xs )(take (middle xs + 1) xs)
valueOdd xs = reorder xs ++ takes xs ++ takeX xs
paruno xs = drop (middle xs + 1) xs
pairTwo xs = take (addOne xs) xs
midPair xs = take (addOne xs)(drop (middle xs -1) xs)
--Get the numbers
midNums xs = if modulus xs == 0 then midPair xs ++ paruno xs ++ pairTwo xs
else valueOdd xs
I want it to work like this: Demo
Try this:
f :: (Num a) => [a] -> [a]
f [] = []
f [x] = [x]
f xs = if len `mod` 2 == 1 then flatten [xs !! half] else flatten [xs !! (half-1), xs !! half]
where len = length xs
half = len `div` 2
firsthalf = take (half-1) xs
secondhalf = (reverse . take half . drop (half+1)) xs
outtoin = zipWith (\x y -> x:y:[]) firsthalf secondhalf
flatten = concat . flip (:) outtoin
Breaking it down:
First get the midpoint(s)
Next get the two halves of the list excluding middle elements
Build the list from outside inwards using zip
Concatenate the zip result to flatten and add to the middle elements list
Demo
So I'm learning haskell right now, and I'm having trouble understanding what I'm doing wrong for the following function that emulates zip
1.ziplike xs ys = [(x,y)|c<-[0..(min (length xs) (length ys))-1],x<-xs!!c,y<-ys!!c]
2.ziplike xs ys = [(xs!!c,ys!!c)|c<-[0..(min (length xs) (length ys))-1]]
Now, I know that the correct answer is number 2, but I don't understand why number 1 is wrong for the call ziplike [1,2,3] ['a', 'b', 'c', 'd']. I THINK it's because it's trying to select the index for an individual char, but I'm not sure why.
The error is "Couldn't match expected type ‘[t1]’ with actual type ‘Char’"
To a first approximation:
If e::[a],
and x <- e appears to the right of the | in a list comprehension,
then x :: a wherever it is bound.
This leads to a bit of a problem in your case. You have ys :: [Char] and c :: Int, so that ys!!c :: Char. Hence:
We have ys!!c :: Char
and y <- ys!!c appears to the right of the | in a list comprehension,
so y :: ??? wherever it is bound.
But now we are stuck when trying to write the conclusion about what type y should have: Char is not a list of as, no matter what a we pick.
There are several possible fixes; one is to use let instead of <-, as in
ziplike xs ys = [(x,y)|c<-[0..min (length xs) (length ys)-1],let x=xs!!c; y=ys!!c]
It's a type error.
When you write "x from xs get-index c" (i.e. x <- xs !! c) the thing that you are getting "from" xs !! c is not necessarily a list. It's a technical detail, but it's important. The "from" arrow comes from monad syntax/do-notation. A list comprehension is actually just a do-expression specialized to the List monad; so the right hand side of an arrow <- needs to be a list in the List monad.
You can fix this, first off, by "cheating" with singleton lists, a la:
ziplike xs ys = [ (x,y) | c <- [0 .. min (length xs) (length ys) - 1],
x <- [xs !! c],
y <- [ys !! c]]
So these left-arrows are not "let" variable bindings, but they make Cartesian products: but the Cartesian product of n things with 1 thing with 1 thing is just n * 1 * 1 == n things. So this is great, if a little weird and possibly inefficient.
To do what you were trying to do (bind x and y inside of the list comprehension) you could also write something like:
ziplike xs ys = [let x = xs !! c; y = ys !! c in (x, y)
| c <- [0 .. min (length xs) (length ys) - 1]]
-- or --
ziplike xs ys = [(x, y)
| c <- [0 .. min (length xs) (length ys) - 1],
let x = xs !! c, let y = ys !! c]
-- or --
ziplike xs ys = [(x, y)
| c <- [0 .. min (length xs) (length ys) - 1],
let x = xs !! c; y = ys !! c]
Notice that these are all do-notation ideas tacked together with commas. Of course all of these look more clumsy than
ziplike xs ys = [(xs !! c, ys !! c) | c <- [0..min (length xs) (length ys) - 1]
which does the exact same thing.
With that said, all of this stuff is much more inefficient than the zip function's recursive character: if I double the size of the list, your implementations take 4 times as long to process the whole list; zip only takes twice as long. So be mindful of this "hidden O(n2) factor" in your programming.
I need a function that does the same thing as itertools.combinations(iterable, r) in python
So far I came up with this:
{-| forward application -}
x -: f = f x
infixl 0 -:
{-| combinations 2 "ABCD" = ["AB","AC","AD","BC","BD","CD"] -}
combinations :: Ord a => Int -> [a] -> [[a]]
combinations k l = (sequence . replicate k) l -: map sort -: sort -: nub
-: filter (\l -> (length . nub) l == length l)
Is there a more elegant and efficient solution?
xs elements taken n by n is
mapM (const xs) [1..n]
all combinations (n = 1, 2, ...) is
allCombs xs = [1..] >>= \n -> mapM (const xs) [1..n]
if you need without repetition
filter ((n==).length.nub)
then
combinationsWRep xs n = filter ((n==).length.nub) $ mapM (const xs) [1..n]
(Based on #JoseJuan's answer)
You can also use a list comprehension to filter out those where the second character is not strictly smaller than the first:
[x| x <- mapM (const "ABCD") [1..2], head x < head (tail x) ]
(Based on #FrankSchmitt’s answer)
We have map (const x) [1..n] == replicate n x so we could change his answer to
[x| x <- sequence (replicate 2 "ABCD"), head x < head (tail x) ]
And while in original question, 2 was a parameter k, for this particular example would probably not want to replicate with 2 and write
[ [x1,x2] | x1 <- "ABCD", x2 <- "ABCD", x1 < x2 ]
instead.
With a parameter k things are a bit more tricky if you want to generate them without duplicates. I’d do it recursively:
f 0 _ = [[]]
f _ [] = []
f k as = [ x : xs | (x:as') <- tails as, xs <- f (k-1) as' ]
(This variant does not remove duplicates if there are already in the list as; if you worry about them, pass nub as to it)
This SO answer:
subsequences of length n from list performance
is the fastest solution to the problem that I've seen.
compositions :: Int -> [a] -> [[a]]
compositions k xs
| k > length xs = []
| k <= 0 = [[]]
| otherwise = csWithoutHead ++ csWithHead
where csWithoutHead = compositions k $ tail xs
csWithHead = [ head xs : ys | ys <- compositions (k - 1) $ tail xs ]
I have written a function to compute the median value of a list
task3 xs | null xs = Nothing
| odd len = xs !! mid
| even len = evenMedian
where len = length xs
mid = len `div` 2
evenMedian = (xs !! mid + xs !! (mid+1)) / 2
I thought it is right and it also pass the load. But when I use the function, it did not work.
What is wrong here?
As Lee mentioned, the list must be sorted first.
(The median of [1,1,8,1,1] is 1 (not 8). so you have to sort it to [1,1,1,1,8] and then take the one in the middle).
The other thing is, that you return Nothing, so the other results have to be of type Maybe a too:
Just $ xs !! mid
Just evenMedian
You can use sort from Data.List to sort your list before applying it to task3.
Like so:
task xs = task3 (sort xs)
How about Median of Medians? Note that this computes only an approximation to the median.
Here is a Haskell implementation:
import Data.List
median :: Ord a => [a] -> a
median xs = select (length xs `div` 2) xs
select :: Ord a => Int -> [a] -> a
select i xs
| n <= 5
= sort xs !! i
| lengthLower == i
= medianOfMedians
| lengthLower < i
= select (i - lengthLower - 1) upperPartition
| otherwise
= select i lowerPartition
where
n = length xs
medianOfMedians = median (map median (chunksOf 5 xs))
(lowerPartition, _:upperPartition) = partition (< medianOfMedians) xs
lengthLower = length lowerPartition
chunksOf :: Int -> [a] -> [[a]]
chunksOf _ [] = []
chunksOf n xs
| (beginning, rest) <- splitAt n xs
= beginning : chunksOf n rest
Recursion could do the job also.
import Data.List
medianFromSorted :: Fractional a => [a] -> Maybe a
medianFromSorted [] = Nothing
medianFromSorted [a] = Just a
medianFromSorted [a,b] = Just ((a + b) / 2)
medianFromSorted (a:xs) = medianFromSorted (init xs) -- init is not efficient
median :: Ord a => Fractional a => [a] -> Maybe a
median = medianFromSorted . sort
My version of median for Integer
import Data.List (sort)
getMiddle [] = 0
getMiddle xs = (a' + b') `div` 2
where a' = head $ drop a xs
b' = head $ drop b xs
a = (n `div` 2)
b = n' - 1
n' = n `div` 2
n = length xs
median :: [Integer] -> Integer
median [] = 0
median xs = result
where result = if (n `mod` 2 == 0)
then getMiddle sorted
else head $ drop a sorted
a = (n - 1) `div` 2
n = length xs
sorted = sort xs
main = print $ median [1, 4, 5, 7, 9, 100]
-- 6
Even with kaan's answer, this code will still not produce a correct median. Another issue that has been overlooked is that Haskell lists are zero indexed. As a result, all of the code is correct with kaan's additions except
evenMedian = (xs !! mid + xs !! (mid+1)) / 2
which should actually be
evenMedian = (xs !! (mid - 1) + xs !! mid) / 2
Otherwise the result is incorrect. The wrong way produces task3 [1, 2, 3, 4] == Just 3.5, while the correct way produces task3 [1, 2, 3, 4] == Just 2.5