Related
I have a Haskell function that computes subsets of a set.
subsets :: [a] -> [[a]]
subsets [] = [[]]
subsets (x:xs) = [zs | ys <- subsets xs, zs <- [ys, (x:ys)]]
Example of use:
*Main> subsets [1,2,3]
[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
If I add the definition:
ksubsets k xs = [ys | ys<-subsets xs, length ys==k]
I can compute the subsets of a set of n elements where each subset has exactly k elements
Example of use:
*Main> ksubsets 3 [1,2,3,4,5]
[[1,2,3],[1,2,4],[1,3,4],[2,3,4],[1,2,5],[1,3,5],[2,3,5],[1,4,5],[2,4,5],
[3,4,5]]
How could I create a more efficient function that generates the subsets of a set with n elements having exactly k elements but without generating all of the subsets. How do I only find the subsets of k elements.
Let's consider some recursive definitions, without going into code quite yet.
If you want to get every subset of size n, then you might pick an element, and append that to a subset of size n-1. If we do that for each element, then we should get all subsets of size n. That's a useful starting point!
Let's put that into code now:
-- A base case:
subsetsOfSize 0 _ = [[]]
-- If there are no elements, there are no subsets:
subsetsOfSize _ [] = []
-- The case discussed above:
subsetsOfSize n (x:xs) =
[x : subs | subs <- subsetsOfSize (n-1) xs] -- ones starting with x,
++ subsetsOfSize n xs -- ones starting with other elements.
As for efficiency? That's left to you, since this does look a bit like work you should be doing on your own. What do you think is inefficient about this function? Here are a few ideas:
If the length of a list list is m, and m is less than n, then subsetsOfSize n list = []. Do we check for that already?
It's well-known that ++ is not performant. What could we use instead? Is there a way to 'rephrase' this function?
I'm having trouble with going through a list. I made this code which gives me a list of numbers which are evenly divided by the sum of their digits. For example, consider the number 123: 123/6 = 20.5, so it will not be in the list. One the other hand 280 will be on the list, because 280/10 = 28.
let inaHelper x = (floor(x)`mod`10)+ (floor(x/10)`mod`10)+(floor(x/100)`mod`10)
let ina = [x | x <- [1..999] , x `mod` (inaHelper x) == 0 ]
[1,2,3,4,5,6,7,8,9,10,12,18,20,21,24,27,30,36,40,42,45,48,50,54,60,63,70,72,80,81,84,90,100,102,108,110,111,112,114,117,120,126,132,133,135,140,144,150,152,153,156,162,171,180,190,192,195,198,200,201,204,207,209,210,216,220,222,224,225,228,230,234,240,243,247,252,261,264,266,270,280,285,288,300,306,308,312,315,320,322,324,330,333,336,342,351,360,364,370,372,375,378,392,396,399,400,402,405,407,408,410,414,420,423,432,440,441,444,448,450,460,465,468,476,480,481,486,500,504,506,510,511,512,513,516,518,522,531,540,550,552,555,558,576,588,592,594,600,603,605,612,621,624,629,630,640,644,645,648,660,666,684,690,700,702,704,711,715,720,730,732,735,736,738,756,770,774,777,780,782,792,800,801,803,804,810,820,825,828,832,840,846,864,870,874,880,882,888,900,902,910,912,915,918,935,936,954,960,966,972,990,999]
But my problem now is: from the list above I only want the numbers that will not have a "neighbour" within a gap of 5 units. For example, the number 300 will be in the new list because it's neighbors (288 and 306) are not within the 5 unit gap.
I came up it this code:
let rare = [ x | x <- [ina] , ((x-5) >= [ina-1]) && ((x+5) <= [ina+1]) ]
I'm a beginner, can someone help?
An easy, though not very efficient, way would be to make a helper function which checks whether there is an element of a list within a certain range:
hasElemInRange :: (Int,Int) -> [Int] -> Bool
hasElemInRange (lo, hi) xs = -- left as exercise
(hint: you can use the any function)
and then you can include it in your list comprehension:
let rare = [ x | x <- ina, hasElemInRange (x-5,x+5) ina ]
Another idiom that you might consider is zipping a list with its own tail. So you can do:
ghci> let xs = [1,2,3,4,5,6,7]
ghci> zip3 xs (tail xs) (tail (tail xs))
[(1,2,3),(2,3,4),(3,4,5),(4,5,6),(5,6,7)]
Which will give you each element of the list with its "context", the element just before and after. Maybe you can figure out how to use that for what you need.
So i've got this function to swap pairs of numbers in haskell, and i don't know what i've done wrong, maybe you guys can give me a hand.
SO basically this function gets a list, say, [1,2,3,4,5], and returns the numbers swapped by pairs, something like, [2,1,4,3,5]. if the number of elements is odd, the last element stays the same.
Here's what i've done:
swapPairs :: [a] -> [a]
swapPairs (x:xs) = [!!x = !!x+1 && !!x+1 = !!x| x <- xs]
-- Return first two elements in inverted order, recusively call for remaining list,
-- only matches lists of two or more elements
swapPairs (a:b:xs) = b : a : swapPairs xs
-- Return tail for zero or one remaining elements
swapPairs (xs) = xs
You can use pattern matching to fetch 2 head elements:
swapPairs (x:y:xs) = y : x : (swapPairs xs)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Split list and make sum from sublist?
Im trying to solve this problem.
I need to do a sum of elements from a list which are separated from each other only with "0".
So for example I can have something like this as input: [1,2,3,0,3,4,0,2,1]
and the output should be [6,7,3].
So far I managed to do something like this:
cut (x:xs) | x > 0 = x : (cut xs)
| otherwise = []
first (xs) = ( (foldl (+) 0 (cut (xs))) ) : []
second (xs) = ( (foldl (+) 0 (cut (reverse (xs)))) ) : []
test (xs) = first(xs) ++ second(xs)
Problem is that this only works with only 1 instance of "0" in my list.
I was trying to solve this by editing my cut function:
cut [] = []
cut (x:xs) | x > 0 = foldl (+) 0 ( x : cut xs) : []
| x == 0 = (cut xs)
But I cant figure out how to adjust it, so it will separate the sums. Right now it just throws the sum of all the elements as the output.
You can divide your problem into two tasks
Split a list into parts on zeros.
Sum parts.
For the first task we have Data.List.Split module which exports splitOn function.
It does precisely what we need:
> splitOn [1] [0,0,0,1,0,0,0,1,0]
[[0,0,0],[0,0,0],[0]]
For the second task there is well-known map-function which applies a function to the each element of the list.
In our case this function is sum:
> map sum [[1,2,3],[4,5,6],[7,8,9]]
[6,15,24]
So:
> :m +Data.List.Split
> map sum . splitOn [0] $ [1,2,3,0,3,4,0,2,1]
[6,7,3]
For homework you should definitely follow dave's answer. However, here is a more advanced solution, employing groupBy as poor man's split:
import Data.List (groupBy)
map sum $ groupBy (const (/=0)) list
This might look cute, but note that there are still the zeros at the beginning of the sub-lists present, so you can't use this solution without changes if that matters (e.g if you need products instead of sums)
[Explanation]
groupBy looks if the first element of the current group "fits together" with the current element of the list. In that case the current element will be added to the group, else a new group starts. E.g.
groupBy (\x y -> x `mod` y == 0) [81,3,9,25,5]
--[[81,3,9],[25,5]]
Here the test ist successful for 81 'mod' 3 and 81 'mod' 9, but not for 81 'mod' 25, which starts a new group. Again, 25 'mod' 5 is successful.
But in our case all elements "fit" in the current group as long as they are not 0, so we don't even have to look at the first element. And if a 0 is found, a new group is started.
const (/=0) means just \_ y -> y /= 0, so regardless what the first argument is, it just tests that the second element isn't 0. To see why, look at the definition:
const :: a -> b -> a
const a _ = a
Now our lambda can be written as
\x y -> const (/= 0) x y
As from the const call only the first of the two arguments "survives", we have
\x y -> (/= 0) y
... or...
\_ y -> y /= 0
Even if you're unable to install to install the split package and use Data.List.Split as Matvey suggests, you can still use the general approach:
Split the weird list with 0 separators into a more conventional list of lists.
Sum each list.
So
yourFunction = map sum . split
Now we have to write split.
split :: [Int] -> [[Int]]
In general, when we want to pull a list apart to synthesise something new, we need to use a fold.
split = foldr cons nil where
nil here should be whatever you want split [] to be.
nil = --TODO: exercise for you; clue: NOT []
cons meanwhile combines one of your numbers, with the answer from the previous step of the fold. Obviously, you'll need to do different things depending on whether or not the number is 0.
cons 0 xss = --TODO
cons x (xs : xss) = --TODO; why will this pattern match never fail?
I don't understand why the base case is needed in this:
-- perms :: Ord a => [a] -> [[a]]
perms [] = [[]]
perms xs = [ (x:ps) | x <- xs, ps <- perms (xs \\ [x])]
It seems to me that it should be automatic from the list-comprehension, but then I noticed that:
[ x:y | x<-[], y<-[] ]
evaluates to [], and not [[]], which seems surprising.
Even so, I was also surprised that without the base case it runs, but always gives [], which violates the type signature.
Is there an easy way to trace the execution of a list comprehension? It seems atomic to Debug.Trace.trace.
You can think of <- as use every element from the list in right in the expression in left.
Since [] has no elements the whole list comprehension returns an empty list.
It will be strange if [ x:y | x<-[], y<-[] ] returns [[]] because : takes element and a list. So to generate [[]] y must be [] but then what will be x?
As KennyTM said [] is of type [[a]]. Actually [] is from every type of this kind:
[a] [[a]] [[[a]]] and so on. If it wasn't then there is no way a function to return an empty list.
Anyway it is a very common mistake to forget some brackets and this is why type annotations are necessary.
Let's de-sugar!
[ x:y | x <- [], y <- [] ]
Turns into
do x <- []
y <- []
return (x:y)
Now, more de-sugaring! Yay!
[] >>= \x -> ([] >>= \y -> return (x:y))
iirc, >>= for lists is flip concatMap, and return is simply \x -> [x]
Let's only do a little bit of that replacement.
concatMap (\x -> ([] >>= \y -> return (x:y))) []
There, now do you see? concatMap f [] will obviously evaluate to []. Because concatMap f is just concat . map f. So map f onto the empty list, and then concatenate the results. Except there are no results, so the final evaluation is [].
So it comes down to the meaning of
[ x:y | x<-[], y<-[] ]
The way to read this is, "What are the possible values of x:y, when x has no possible values, and y has no possible values?" Hopefully, it should be clear that in that case, there are no values at all for x:y, since you'd need a value for x and a value for y to get a possibility for x:y, and you have neither.
This general pattern of selecting combinations of possible values for x and y is called a cartesian product, and the word "product" is used in part because the number of possibile combinations is equal to the number of possibilities for x, times the number of possibilities for y. So if there are zero choices for x, and zero choices for y, you can expect 0 * 0 = 0 choices for combinations of the two.
Here's another hint why there is a base case with an empty list. How many permutations are there of n elements? There are n! permutations. And what is 0!? It's 1. So the length of the result list for perm [] has to be 1. The types and the lack of elements of type a forces the result to be [[]]. No other defined value has the right type and length.
If you have a list comprehension of the form:
[ x:y | stuff ]
then you are producing a list whose elements are of the form x:y for some choices of x and y as determined by stuff. [[]] is a list whose elements are not of the form x:y for any x or y, so the former cannot produce the latter.
In expecting [[]] from [ x:y | x <- [], y <- [] ], you seem to be setting x = [] and y = [] and then considering x:y = [[]]. This is wrong for a couple of reasons:
x is coming from xs of type [a], so x has type a, and is not (in general) a list
the result of the list comprehension is a list of x:y elements, not a single one.