Recursion using lists - Haskell - list
I am trying to write a recursive function that will take a list containing a list of integers as an input and return a tuple of type ([Int],Int).
([Int],Int)
This is for a "board game" where you are supplied with a board:
[[5,4,3,8,6],
[0,2,1,0,7],
[0,1,9,4,3],
[2,3,4,0,9]]
This would be a board with 4 rows and 5 columns. The numbers inside the list are "coin values".
The objective of this board game would be to go from the top of the list to the bottom collecting the coins. You are able to start in any position from the top row and to move down, you can go straight down, or diagonally to left or right. You would want the path that will give you the largest total coin values.
I've created a first function where you input a list of paths [([Int],Int)] and it returns the path ([Int],Int) with maximum coin value.
Now I need to create a function to actually generate the list of paths that I will input into the first function.
I know that I will have to use recursion.
I will input the board (like one above) and a starting column.
I will have to take the column number and then create a list of all possible paths.
If I start with a column number, my next possible steps are positions (in the next row)- same column number, column num -1 and column num +1. I would need to recursively call this until I reach the bottom.
How would I be able to store these path steps as I go and then store the final - list of all possible paths?
([Int],Int) - [Int] is the position in list / column numbers or the rows and the Int is the coin value.
I'm new to haskell and while I understand what I have to do, it's really difficult to write the code.
You don't "store" intermediate values in some variable in idiomatic functional code. Rather, you keep them as an accumulating parameter which you pass along using a function such as foldr.
http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:foldr
I guess I am now in a position to (easily) adapt my answer for another question to this one. I listed the allowed index combinations and mapped the board to them. (pat's comment helped me improve index_combinations)
*Main> :load "new1.hs"
[1 of 1] Compiling Main ( new1.hs, interpreted )
Ok, modules loaded: Main.
*Main> result
([8,7,4,9],28)
*Main> path
[3,4,3,4]
import Data.List
import Data.Ord
import Data.Maybe
r = [[5,4,3,8,6],
[0,2,1,0,7],
[0,1,9,4,3],
[2,3,4,0,9]]
r1 = r !! 0
r2 = r !! 1
r3 = r !! 2
r4 = r !! 3
index_combinations =
[[a,b,c,d] | a <- [0..4], b <- [max 0 (a-1)..min 4 (a+1)],
c <- [max 0 (b-1)..min 4 (b+1)], d <- [max 0 (c-1)..min 4 (c+1)]]
mapR xs = [r1 !! (xs !! 0), r2 !! (xs !! 1),
r3 !! (xs !! 2), r4 !! (xs !! 3)]
r_combinations = map mapR index_combinations
r_combinations_summed = zip r_combinations $ map (foldr (+) 0) r_combinations
result = maximumBy (comparing snd) r_combinations_summed
path = index_combinations !! fromJust (elemIndex result r_combinations_summed)
If you're interested in using my package grid (userguide)
here as an example to get you started.
(And if you don't want to use it, you may find some of the
source code helpful.)
Create a grid with 4 rows and 5 columns.
λ> :m + Math.Geometry.Grid
λ> let g = rectSquareGrid 4 5
λ> indices g
[(0,0),(0,1),(0,2),(0,3),(1,0),(1,1),(1,2),(1,3),(2,0),(2,1),(2,2),(2,3),(3,0),(3,1),(3,2),(3,3),(4,0),(4,1),(4,2),(4,3)]
We want to be able to map "coin values" to grid positions, so we'll
create a GridMap.
λ> :m + Math.Geometry.GridMap
λ> let m = lazyGridMap g [5,4,3,8,6,0,2,1,0,7,0,1,9,4,3,2,3,4,0,9]
λ> m
lazyGridMap (rectSquareGrid 4 5) [5,4,3,8,6,0,2,1,0,7,0,1,9,4,3,2,3,4,0,9]
λ> toList m
[((0,0),5),((0,1),4),((0,2),3),((0,3),8),((1,0),6),((1,1),0),((1,2),2),((1,3),1),((2,0),0),((2,1),7),((2,2),0),((2,3),1),((3,0),9),((3,1),4),((3,2),3),((3,3),2),((4,0),3),((4,1),4),((4,2),0),((4,3),9)]
We can find out the neighbours of any cell in the grid,
but for your application, we run into a bit of a problem: my
RectSquareGrid type doesn't allow diagonal moves.
λ> neighbours (1,2) m
[(0,2),(1,3),(2,2),(1,1)]
Now, I'd be happy to create a new type of Grid that would meet your
needs. Alternatively, you could write your own function
which would include diagonal neighbours:
λ> let neighbours2 (x, y) g = filter (`inGrid` g) [(x-1,y-1), (x-1,y), (x-1,y+1), (x,y-1), (x,y+1), (x+1,y-1), (x+1,y), (x+1,y+1)]
λ> neighbours2 (1,2) m
[(0,1),(0,2),(0,3),(1,1),(1,3),(2,1),(2,2),(2,3)]
But you're only interested in allowing downward moves, either straight down or diagonal, so here's a more useful function:
λ> let allowedMoves (x, y) g = filter (`inGrid` g) [(x+1,y-1), (x+1,y), (x+1,y+1)]
λ> allowedMoves (1,2) m
[(2,1),(2,2),(2,3)]
So now we can write a function that gives you all possible paths from a given index to the bottom row of the grid.
allPathsFrom a g | fst a == fst (size g) = [[a]]
| otherwise = Prelude.map (a:) xs
where xs = concatMap (\x -> allPathsFrom x g) ys
ys = allowedMoves a g
For example:
λ> allPathsFrom (0,1) m
[[(0,1),(1,0),(2,0),(3,0),(4,0)],[(0,1),(1,0),(2,0),(3,0),(4,1)],[(0,1),(1,0),(2,0),(3,1),(4,0)],[(0,1),(1,0),(2,0),(3,1),(4,1)],[(0,1),(1,0),(2,0),(3,1),(4,2)],[(0,1),(1,0),(2,1),(3,0),(4,0)],[(0,1),(1,0),(2,1),(3,0),(4,1)],[(0,1),(1,0),(2,1),(3,1),(4,0)],[(0,1),(1,0),(2,1),(3,1),(4,1)],[(0,1),(1,0),(2,1),(3,1),(4,2)],[(0,1),(1,0),(2,1),(3,2),(4,1)],[(0,1),(1,0),(2,1),(3,2),(4,2)],[(0,1),(1,0),(2,1),(3,2),(4,3)],[(0,1),(1,1),(2,0),(3,0),(4,0)],[(0,1),(1,1),(2,0),(3,0),(4,1)],[(0,1),(1,1),(2,0),(3,1),(4,0)],[(0,1),(1,1),(2,0),(3,1),(4,1)],[(0,1),(1,1),(2,0),(3,1),(4,2)],[(0,1),(1,1),(2,1),(3,0),(4,0)],[(0,1),(1,1),(2,1),(3,0),(4,1)],[(0,1),(1,1),(2,1),(3,1),(4,0)],[(0,1),(1,1),(2,1),(3,1),(4,1)],[(0,1),(1,1),(2,1),(3,1),(4,2)],[(0,1),(1,1),(2,1),(3,2),(4,1)],[(0,1),(1,1),(2,1),(3,2),(4,2)],[(0,1),(1,1),(2,1),(3,2),(4,3)],[(0,1),(1,1),(2,2),(3,1),(4,0)],[(0,1),(1,1),(2,2),(3,1),(4,1)],[(0,1),(1,1),(2,2),(3,1),(4,2)],[(0,1),(1,1),(2,2),(3,2),(4,1)],[(0,1),(1,1),(2,2),(3,2),(4,2)],[(0,1),(1,1),(2,2),(3,2),(4,3)],[(0,1),(1,1),(2,2),(3,3),(4,2)],[(0,1),(1,1),(2,2),(3,3),(4,3)],[(0,1),(1,2),(2,1),(3,0),(4,0)],[(0,1),(1,2),(2,1),(3,0),(4,1)],[(0,1),(1,2),(2,1),(3,1),(4,0)],[(0,1),(1,2),(2,1),(3,1),(4,1)],[(0,1),(1,2),(2,1),(3,1),(4,2)],[(0,1),(1,2),(2,1),(3,2),(4,1)],[(0,1),(1,2),(2,1),(3,2),(4,2)],[(0,1),(1,2),(2,1),(3,2),(4,3)],[(0,1),(1,2),(2,2),(3,1),(4,0)],[(0,1),(1,2),(2,2),(3,1),(4,1)],[(0,1),(1,2),(2,2),(3,1),(4,2)],[(0,1),(1,2),(2,2),(3,2),(4,1)],[(0,1),(1,2),(2,2),(3,2),(4,2)],[(0,1),(1,2),(2,2),(3,2),(4,3)],[(0,1),(1,2),(2,2),(3,3),(4,2)],[(0,1),(1,2),(2,2),(3,3),(4,3)],[(0,1),(1,2),(2,3),(3,2),(4,1)],[(0,1),(1,2),(2,3),(3,2),(4,2)],[(0,1),(1,2),(2,3),(3,2),(4,3)],[(0,1),(1,2),(2,3),(3,3),(4,2)],[(0,1),(1,2),(2,3),(3,3),(4,3)]]
Note that since GridMaps are also Grids, we can invoke all of the above functions on m or g.
λ> allPathsFrom (0,1) m
Let me know (amy at nualeargais dot ie) if you would like me to add
a grid allowing diagonal moves to my grid package.
Related
transpose a 2d list and convert it to a 1d list
I have a 2d list l, and [l!!y!!x| x<-[0..length l-1], y<-[0..length l-1]] will produce a 1d list where rows and columns are swapped. How can I implement this without list comprehension(i.e. using map)?
Break down the problem into parts. To transpose a single row, you want to return a column where each row contains a single element. A 1 x n matrix becomes an n x 1 matrix: {- 1 2 ... n 1 2 ... n -} transpose [row] = map (\ x -> [x]) row E.g.: transpose [[1, 2, 3]] = [[1], [2], [3]]. \ x -> [x] can also be written as an operator section (: []) or pure from Applicative. When you pattern-match on the outer list (input rows), you split the top row of the matrix from the remaining rows. The transpose of a matrix is the transposition of the first row prepended to the transposition of the remaining rows. You can join two matrices vertically (i.e. placing one atop the other) with (++) (which could be written as (<>) from Semigroup) or horizontally with zipWith (++) (resp. zipWith (<>)) (i.e. placing one beside the other). Transposed matrices are joined horizontally: {- 1 2 ... n 1 a ... p a b ... c 2 b ... q ....... ......... p q ... r n c ... r -} transpose (top : down) = zipWith (++) (transpose [top]) (transpose down) E.g.: transpose [[1, 2], [3, 4], [5, 6]] = [[1] ++ [3, 5], [2] ++ [4, 6]]. This can also be expressed as zipWith (:) top (transpose down) since we know we have single elements to prepend; this skips some of the redundant effort of wrapping and then immediately unwrapping the elements of the input row / output column. Finally, the transposition of an empty matrix with no rows is also the empty matrix. transpose [] = [] Putting these together: transpose :: [[a]] -> [[a]] transpose [r] = map (: []) r transpose (r : rs) = zipWith (:) r (transpose rs) transpose [] = [] Follow-up: consider how this code responds to the edge cases where the input is non-rectangular or has an infinite number of rows or columns. As Will Ness’s answer makes clear, this recursive function is nearly equivalent to a right fold, where the combining function is the prepending of columns by zipWith (:), and the base accumulator is the empty column of indefinite height, repeat [], i.e. transpose m = foldr (zipWith (:)) (repeat []) m, or eta-reduced, transpose = foldr (zipWith (:)) (repeat []). However, they differ in an edge case: the fold produces an infinite list when given an empty input. That version is also equivalent to getZipList . traverse ZipList, based on the observation that traverse id :: (Traversable t, Applicative f) => t (f b) -> f (t b) is a kind of generalised transposition.
Since you wanted it without explicit recursion, zipWith is also a binary map of sorts (and in some other languages map actually can take any number of argument lists). Hence, transposed = foldr (zipWith (:)) (repeat []) Trying it: > transposed [[1,2,3],[11,12,13],[21,22,23,24]] [[1,11,21],[2,12,22],[3,13,23]] This can be simply composed with concat :: [[a]] -> [a] to concatenate the transposed lists.
We can work with recursion for this: each time we yield the heads of the lists, and then recurse on the tails, so: catTranspose :: [[a]] -> [a] catTranspose ([]:_) = [] catTranspose xs = map head xs ++ … where I leave filling in … as an exercise. It should make a recursive call where we map each item in xs to its tail. If the list is rectangular, this will work, for non-rectangular 2d lists, you will need to work with functions that are more safe, and thus will not error like head does on an empty list. One can also drop the explicit recursion and work for example with unfoldr :: (b -> Maybe (a, b)) -> b -> [a] and concat :: Foldable f => f [a] -> [a] that will then perform the recursion.
permutation in a list with repetition ocaml
I have a function that makes combinations of K distinct objects chosen from the N elements of a list, the problem is doesn't permute with repetition, for example: extract 2 ["a";"b";"c";"d"];; - : string list list = [["a"; "b"]; ["a"; "c"]; ["a"; "d"]; ["b"; "c"]; ["b"; "d"]; ["c"; "d"]] Here is my code: # let rec extract k list = if k <= 0 then [ [] ] else match list with | [] -> [] | h :: tl -> let with_h = List.map (fun l -> h :: l) (extract (k-1) tl) in let without_h = extract k tl in with_h # without_h;; I'm trying figure out how would do that, thanks for replying.
I have a function that makes combinations of K distinct objects Indeed. the problem is doesn't permute with repetition, It's not much more difficult than combinations. There are two ways to go about your inductive step. If you want to permute k elements of a (non-empty) set A you can: Method 1 For every element x in A, calculate the permutations of k-1 elements of A\{x} and put x in front of all those permutations. Then join the sets of solutions you obtained for each x. Method 2 Choose one x in A, calculate the permutations of k-1 elements of A\{x}, then for each permutation found calculate new ones by inserting x in each possible position.
Haskell - split a list into two sublists with closest sums
I'm a Haskell beginner trying to learn more about the language by solving some online quizzes/problem sets. The problem/question is quite lengthy but a part of it requires code that can find the number which divides a given list into two (nearly) equal (by sum) sub-lists. Given [1..10] Answer should be 7 since 1+2+..7 = 28 & 8+9+10 = 27 This is the way I implemented it -- partitions list by y partishner :: (Floating a) => Int -> [a] -> [[[a]]] partishner 0 xs = [[xs],[]] partishner y xs = [take y xs : [drop y xs]] ++ partishner (y - 1) xs -- finds the equal sum findTheEquilizer :: (Ord a, Floating a) => [a] -> [[a]] findTheEquilizer xs = fst $ minimumBy (comparing snd) zipParty where party = (tail . init) (partishner (length xs) xs) -- removes [xs,[]] types afterParty = (map (\[x, y] -> (x - y) ** 2) . init . map (map sum)) party zipParty = zip party afterParty -- zips partitions and squared diff betn their sums Given (last . head) (findTheEquilizer [1..10]) output : 7 For numbers near 50k it works fine λ> (last . head) (findTheEquilizer [1..10000]) 7071.0 The trouble starts when I put in lists with any more than 70k elements in it. It takes forever to compute. So what do I have to change in the code to make it run better or do I have to change my whole approach? I'm guessing it's the later, but I'm not sure how to go about do that.
It looks to me that the implementation is quite chaotic. For example partishner seems to construct a list of lists of lists of a, where, given I understood it correctly, the outer list contains lists with each two elements: the list of elements on "the left", and the list of elements at the "right". As a result, this will take O(n2) to construct the lists. By using lists over 2-tuples, this is also quite "unsafe", since a list can - although here probably impossible - contain no elements, one element, or more than two elements. If you make a mistake in one of the functions, it will be hard to find out that mistake. It looks to me that it might be easier to implement a "sweep algorithm": we first calculate the sum of all the elements in the list. This is the value on the "right" in case we decide to split at that specific point, next we start moving from left to right, each time subtracting the element from the sum on the right, and adding it to the sum on the left. We can each time evaluate the difference in score, like: import Data.List(unfoldr) sweep :: Num a => [a] -> [(Int, a, [a])] sweep lst = x0 : unfoldr f x0 where x0 = (0, sum lst, lst) f (_, _, []) = Nothing f (i, r, (x: xs)) = Just (l, l) where l = (i+1, r-2*x, xs) For example: Prelude Data.List> sweep [1,4,2,5] [(0,12,[1,4,2,5]),(1,10,[4,2,5]),(2,2,[2,5]),(3,-2,[5]),(4,-12,[])] So if we select to split at the first split point (before the first element), the sum on the right is 12 higher than the sum on the left, if we split after the first element, the sum on the right (11) is 10 higher than the sum on the left (1). We can then obtain the minimum of these splits with minimumBy :: (a -> a -> Ordering) -> [a] -> a: import Data.List(minimumBy) import Data.Ord(comparing) findTheEquilizer :: (Ord a, Num a) => [a] -> ([a], [a]) findTheEquilizer lst = (take idx lst, tl) where (idx, _, tl) = minimumBy (comparing (abs . \(_, x, _) -> x)) (sweep lst) We then obtain the correct value for [1..10]: Prelude Data.List Data.Ord Data.List> findTheEquilizer [1..10] ([1,2,3,4,5,6,7],[8,9,10]) or for 70'000: Prelude Data.List Data.Ord Data.List> head (snd (findTheEquilizer [1..70000])) 49498 The above is not ideal, it can be implemented more elegantly, but I leave this as an exercise.
Okay, firstly, let analyse why it run forever (...actually not forever, just slow), take a look of partishner function: partishner y xs = [take y xs : [drop y xs]] ++ partishner (y - 1) xs where take y xs and drop y xs are run linear time, i.e. O(N), and so as [take y xs : [drop y xs]] is O(N) too. However, it is run again and again in recursive way over each element of given list. Now suppose the length of given list is M, each call of partishner function take O(N) times, to finish computation need: O(1+2+...M) = (M(1+M)/2) ~ O(M^2) Now, the list has 70k elements, it at least need 70k ^ 2 step. So why it hang. Instead of using partishner function, you can sum the list in linear way as: sumList::(Floating a)=>[a]->[a] sumList xs = sum 0 xs where sum _ [] = [] sum s (y:ys) = let s' = s + y in s' : sum s' ys and findEqilizer just sum the given list from left to right (leftSum) and from right to left (rightSum) and take the result just as your original program, but the whole process just take linear time. findEquilizer::(Ord a, Floating a) => [a] -> a findEquilizer [] = 0 findEquilizer xs = let leftSum = reverse $ 0:(sumList $ init xs) rightSum = sumList $ reverse $ xs afterParty = zipWith (\x y->(x-y) ** 2) leftSum rightSum in fst $ minimumBy (comparing snd) (zip (reverse $ init xs) afterParty)
I assume that none of the list elements are negative, and use a "tortoise and hare" approach. The hare steps through the list, adding up elements. The tortoise does the same thing, but it keeps its sum doubled and it carefully ensures that it only takes a step when that step won't put it ahead of the hare. approxEqualSums :: (Num a, Ord a) => [a] -> (Maybe a, [a]) approxEqualSums as0 = stepHare 0 Nothing as0 0 as0 where -- ht is the current best guess. stepHare _tortoiseSum ht tortoise _hareSum [] = (ht, tortoise) stepHare tortoiseSum ht tortoise hareSum (h:hs) = stepTortoise tortoiseSum ht tortoise (hareSum + h) hs stepTortoise tortoiseSum ht [] hareSum hare = stepHare tortoiseSum ht [] hareSum hare stepTortoise tortoiseSum ht tortoise#(t:ts) hareSum hare | tortoiseSum' <= hareSum = stepTortoise tortoiseSum' (Just t) ts hareSum hare | otherwise = stepHare tortoiseSum ht tortoise hareSum hare where tortoiseSum' = tortoiseSum + 2*t In use: > approxEqualSums [1..10] (Just 6,[7,8,9,10]) 6 is the last element before going over half, and 7 is the first one after that.
I asked in the comment and OP says [1..n] is not really defining the question. Yes i guess what's asked is like [1 -> n] in random ascending sequence such as [1,3,7,19,37,...,1453,...,n]. Yet..! Even as per the given answers, for a list like [1..n] we really don't need to do any list operation at all. The sum of [1..n] is n*(n+1)/2. Which means we need to find m for n*(n+1)/4 Which means m(m+1)/2 = n*(n+1)/4. So if n == 100 then m^2 + m - 5050 = 0 All we need is formula where a = 1, b = 1 and c = -5050 yielding the reasonable root to be 70.565 ⇒ 71 (rounded). Lets check. 71*72/2 = 2556 and 5050-2556 = 2494 which says 2556 - 2494 = 62 minimal difference (<71). Yes we must split at 71. So just do like result = [[1..71],[72..100]] over..! But when it comes to not subsequent ascending, that's a different animal. It has to be done by first finding the sum and then like binary search by jumping halfway the list and comparing the sums to decide whether to jump halfway back or forward accordingly. I will implement that one later.
Here's a code which is empirically behaving better than linear, and gets to the 2,000,000 in just over 1 second even when interpreted: g :: (Ord c, Num c) => [c] -> [(Int, c)] g = head . dropWhile ((> 0) . snd . last) . map (take 2) . tails . zip [1..] . (\xs -> zipWith (-) (map (last xs -) xs) xs) . scanl1 (+) g [1..10] ==> [(6,13),(7,-1)] -- 0.0s g [1..70000] ==> [(49497,32494),(49498,-66502)] -- 0.09s g [70000,70000-1..1] ==> [(20502,66502),(20503,-32494)] -- 0.09s g [1..100000] ==> [(70710,75190),(70711,-66232)] -- 0.11s g [1..1000000] ==> [(707106,897658),(707107,-516556)] -- 0.62s g [1..2000000] ==> [(1414213,1176418),(1414214,-1652010)] -- 1.14s n^0.88 g [1..3000000] ==> [(2121320,836280),(2121321,-3406362)] -- 1.65s n^0.91 It works by running the partial sums with scanl1 (+) and taking the total sum as its last, so that for each partial sum, subtracting it from the total gives us the sum of the second part of the split. The algorithm assumes all the numbers in the input list are strictly positive, so the partial sums list is monotonically increasing. Nothing else is assumed about the numbers. The value must be chosen from the pair (the g's result) so that its second component's absolute value is the smaller between the two. This is achieved by minimumBy (comparing (abs . snd)) . g. clarifications: There's some confusion about "complexity" in the comments below, yet the answer says nothing at all about complexity but uses a specific empirical measurement. You can't argue with empirical data (unless you misinterpret its meaning). The answer does not claim it "is better than linear", it says "it behaves better than linear" [in the tested range of problem sizes], which the empirical data incontrovertibly show. Finally, an appeal to authority. Robert Sedgewick is an authority on algorithms. Take it up with him. (and of course the algorithm handles unordered data as well as it does ordered). As for the reasons for OP's code inefficiency: map sum . inits can't help being quadratic, but the equivalent scanl (+) 0 is linear. The radical improvement comes about from a lot of redundant calculations in the former being avoided in the latter. (Another example of this can be seen here.)
Partitioning a list fairly
I'm sure this is a reasonably common thing but I can't find anything on it (my internet-search-fu is not strong). I have a function that can group a list into a list of lists of N elements each, with the final sublist being smaller than N if the length of the list is not evenly divisible by N. Some examples: groupEvery 2 [1,2,3,4] = [[1,2],[3,4]] groupEvery 4 [1,2,3,4,5,6,7,8,9,10] = [[1,2,3,4], [5,6,7,8], [9,10]] What I want is to take a list and a positive integer n (in the above examples n could be said to be 2 and 3) and partition it into a new list of n lists. It should work on a list of any type, and produce sublists whose sizes differ as little as possible. So I would like to have: fairPartition 3 [1,2,3,4,5,6,7,8,9,10] = [[1,2,3,4], [5,6,7], [8,9,10]] Or any combination of sublists as long as there are two of length 3 and one of length 4. A naive attempt using groupEvery: fairPartition :: Int -> [a] -> [[a]] fairPartition n xs = groupEvery ((length xs `div` n) + 1) xs fairPartition 4 [1..10] = [[1,2,3],[4,5,6],[7,8,9],[10]] but as you can see (3,3,3,1) is not a fair distribution of lengths, and for lists of smaller lengths it doesn't even return the right number of sublists: # Haskell, at GHCi *Main> let size = 4 in map (\l -> length . fairPartition 4 $ [1..l]) [size..25] [2,3,3,4,3,3,4,4,3,4,4,4,4,4,4,4,4,4,4,4,4,4] I would like a {pseudo,actual}-code function or explanation that is easily translatable to Haskell (the identity translation would be the best!). Thanks.
You can use the split package's splitPlaces function for this. import Data.List.Split fairPartition n xs = case length xs `quotRem` n of (q, r) -> splitPlaces (replicate r (q+1) ++ replicate (n-r) q) xs
Haskell: List Boundary
I have a list of doubles(myList), which I want to add to a new List (someList), but once the new list reaches a set size i.e. 25, I want to stop adding to it. I have tried implementing this function using sum but was unsuccessful. Example code below. someList = [(a)| a <- myList, sum someList < 30]
The way #DanielFischer phrased the question is compatible with the Haskell way of thinking. Do you want someList to be the longest prefix of myList that has a sum < 30? Here's how I'd approach it: let's say our list is >>> let list = [1..20] we can find the "cumulative sums" using: >>> let sums = tail . scanl (+) 0 >>> sums list [1,3,6,10,15,21,28,36,45,55,66,78,91,105,120,136,153,171,190,210] Now zip that with the original list to get pairs of elements with the sum up to that point >>> zip list (sums list) [(1,1),(2,3),(3,6),(4,10),(5,15),(6,21),(7,28),(8,36), (9,45),(10,55),(11,66),(12,78),(13,91),(14,105),(15,120), (16,136),(17,153),(18,171),(19,190),(20,210)] Then we can takeWhile this list to get the prefix we want: >>> takeWhile (\x -> snd x < 30) (zip list (sums list)) [(1,1),(2,3),(3,6),(4,10),(5,15),(6,21),(7,28)] finally we can get rid of the cumulative sums that we used to perform this calculation: >>> map fst (takeWhile (\x -> snd x < 30) (zip list (sums list))) [1,2,3,4,5,6,7] Note that because of laziness, this is as efficient as the recursive solutions -- only the sums up to the point where they fail the test need to be calculated. This can be seen because the solution works on infinite lists (because if we needed to calculate all the sums, we would never finish). I'd probably abstract this and take the limit as a parameter: >>> :{ ... let initial lim list = ... map fst (takeWhile (\x -> snd x < lim) (zip list (sums list))) ... :} This function has an obvious property it should satisfy, namely that the sum of a list should always be less than the limit (as long as the limit is greater than 0). So we can use QuickCheck to make sure we did it right: >>> import Test.QuickCheck >>> quickCheck (\lim list -> lim > 0 ==> sum (initial lim list) < lim) +++ OK, passed 100 tests.
someList = makeList myList [] 0 where makeList (x:xs) ys total = let newTot = total + x in if newTot >= 25 then ys else makeList xs (ys ++ [x]) newTot This takes elements from myList as long as their sum is less than 25. The logic takes place in makeList. It takes the first element of the input list and adds it to the running total, to see if it's greater than 25. If it is, we shouldn't add it to the output list, and we finish recursing. Otherwise, we put x on the end of the output list (ys) and keep going with the rest of the input list.
The behaviour you want is ghci> appendWhileUnder 25 [1..5] [1..5] [1,2,3,4,5,1,2,3] because that sums to 21 and adding the 4 would bring it to 25. OK, one way to go about this is by just appending them with ++ then taking the initial segment that's under 25. appendWhileUnder n xs ys = takeWhileUnder n (xs++ys) I don't want to keep summing intermediate lists, so I'll keep track with how much I'm allowed (n). takeWhileUnder n [] = [] takeWhileUnder n (x:xs) | x < n = x:takeWhileUnder (n-x) xs | otherwise = [] Here I allow x through if it doesn't take me beyond what's left of my allowance. Possibly undesired side effect: it'll chop out bits of the original list if it sums to over 25. Workaround: use appendWhileUnder' n xs ys = xs ++ takeWhileUnder (n - sum xs) which keeps the entire xs whether it brings you over n or not.