How do I sequence a list of tuples? - haskell

I'm trying to sequence a list of (Int, Int) tuples into a list of int lists [[Int]]
Why? I've found many use cases for this. Basically given a list like so:
[(1,5), (2,3), (3,4), (4,5), (6,7), (7,8)]
I want to return a list:
[[1,2,3,4,5],[6,7,8]]
Here's what I have so far:
pieces :: [(Int, Int)]
pieces = [(1,5), (2,3), (3,4), (4,5), (6,7), (7,8)]
linkStep :: [[Int]] -> (Int, Int) -> [[Int]]
linkStep (x:xs) (a, b)
| elem a x = (b : x) : xs
| elem b x = (a : x) : xs
| otherwise = (a : b : x) : xs
-- Now I fold the linkStep function over the list
links :: [(Int, Int)] -> [[Int]]
links list = foldl linkStep [[]] list
However when I call links with pieces I get
links pieces
--[[8,6,7,5,4,2,3,1,5]]
I'm not really sure what I'm doing wrong. The linkStep function is supposed to concatenate a tuple element that is in the resulting list to the target list in the result. If the tuple element is not yet in the resulting list a new list with the tuple element is added. But its not working... Please help!

There are a couple of issues that I see:
In linkStep, you only ever check if your tuple elements are members of the first inner list. From your example, it looks as if you're going to need to check all the lists, not just the first one.
In the cases of linkStep, you always add a, b, or both a and b to the first inner list. Thus all elements will eventually end up in the first list. Maybe you meant to create a new list here instead? But it might also be a good place to consider other lists than the first.
Hopefully this will help you to make progress.

Related

Haskell, taking a list of pairs (value,index) and making it a single list [Int]

I am fairly new at Haskell and have been trying to solve this.
I have been trying to take a list of pairs and condense it down to a single list
For example if I had the pairs:
[(2,0),(4,5),(3,10)]
The list should return
[2,0,0,0,0,4,0,0,0,0,3]
The idea is that the first element of the pair is the value and the second value is the index.
Here is what I have tried so far:
finalList :: [(Int,Int)] -> [Int]
finalList ((x,y): xs) = replicate y 0 ++ [x] ++ finalList xs
finalList _ = []
However with this issue I am not getting the desired padding of 0s that I would like to have . I am instead getting something like:
[6,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,12]
Any help would be greatly appreciated! Thanks!
I will provide a hint. I will also assume that the indices in the input list are in increasing order.
A possible approach is to first define an auxiliary function that takes one more argument, an "index" counting how many elements we have produces so far. Here is a sketch of a part of the code you might use.
f :: [(Int,Int)] -> Int -> [Int]
f [] _ = ... -- base case
f ((value, pos):xs) ix
| ix == pos = value : ... -- here we recurse
| otherwise = 0 : ... -- here we recurse too
Roughly put, the logic above is: keep track of the current position ix: if the position is the wanted one pos, emit value. Otherwise emit 0 as a filler.
In both cases we recurse, and we need to increment the current position ix. The current position is will be initially set to zero as follows:
finalList :: [(Int,Int)] -> [Int]
finalList xs = f xs 0
Note that when we recurse, we also need to understand what to do with the input list. I will leave that to you.

Find connected components from lists of edges

I need to find the connected components of a graph given its edges.
The graph edges are represented as a list of tuples, and the result needs to be a list of lists of vertices representing the connected components,
eg [(1,2), (2,3), (2,6), (5,6) (6,7), (8,9), (9,10)] -> [[1,2,3,5,6,7], [8,9,10]].
There could be any number of connected edges and unconnected graph components in the list. The tuples will always be in ascending order though, if that helps.
I have the signature groupEdges :: [(Int, Int)] -> [[Int]] but I just can't think of how to get from tuples to lists.
I thought of taking one tuple at a time and searching the rest for matching elements, but I don't know how to make this list of sublists.
This question is similar to this question on the CS Stack Exchange, but I don't want to use Data.Graph. I would like to do this without other packages if possible.
-- edit - comments from chepner and ThibautM have given me the first step. I can convert from tuples to lists by calling the function with groupEdges map (\(x,y) -> [x,y]) pairs.
Now I need to take this list of lists and group the connected components eg. [[1,2], [2,3], [2,6], [5,6], [6,7], [8,9], [9,10]] -> [[1,2,3,5,6,7], [8,9,10]]
You mentioned not using packages. The 4 functions I used are relatively easy to implement yourself if you really want. (And I encourage you to either do so or at least lookup their implementation)
Lists are used as set, which is a lot worse in performance than using a dedicated structure e.g. Data.Set. Using a disjoint-set (union-find, merge-find) data structure (referenced in your linked answer) would be even better, but probably not very good as a starting point for understanding
import Data.List (elem, intersect, union, partition)
pairs = [(1,2), (2,3), (2,6), (5,6), (6,7), (8,9), (9,10)]
pairs2 = map (\(x,y) -> [x,y]) pairs
-- add item to list, only if its no already present - using list as set
addItem item list | elem item list = list
| otherwise = item : list
-- used to test whether subgraphs are connected i.e. contain common node
intersects a b = not $ null $ intersect a b
unionAll :: (Eq a) => [[a]] -> [a]
unionAll (x1:x2:xs) = unionAll ((union x1 x2):xs)
unionAll [x] = x
unionAll [] = []
-- find edges that are connected to first edge/subgraph and merge them
groupFirst :: (Eq a) => [[a]] -> [[a]]
groupFirst (x:xs) = (unionAll (x:connected)) : disconnected
where
-- separate 'xs' edges/subgraphs into those that are connected to 'x' and the rest
(connected, disconnected) = partition (intersects x) xs
groupFirst [] = []
-- if no more edges/subgraphs can be connected with first edge, continue with remaining (disconnected) edge/subgraph ([5,6] in second iteration)
groupAll :: (Eq a) => [[a]] -> [[a]]
groupAll (x:xs) = y:(groupAll ys)
where
(y:ys) = groupFirst (x:xs)
groupAll [] = []
-- after first 'groupAll pairs2' - [[1,2,3,6],[5,6,7],[8,9,10]]
-- repeat this process until no more components can be connected together
groupAllRepeat x = if x /= groupAll x then groupAllRepeat (groupAll x) else x
main = print (groupAllRepeat pairs2)

How to list all possible ways to pair up a list?

I'm new to Haskell and need to list all possible ways to pair up (even) lists of Ints.
E.g.
[1,2,3,4] -> [[(1,2),(3,4)], [(2,3),(1,4)], [(1,3),(2,4)], ...]
Generating all possible pairs is easy enough (shown below) but I can't work out how to return only ways to pair up the entire input list.
pairs :: [a] -> [[(a, a)]]
pairs l = [(x,y) | (x:ys) <- tails l, y <- ys]
I recommend writing a function that nondeterministically chooses an element, returning the rest of the values in the list as well. There are a few possible APIs; the one I suggest below is the most general-purpose one, and one I've used on many occasions for apparently unrelated tasks.
zippers :: [a] -> [([a], a, [a])]
Here's an example of what this function does:
> zippers "abcd"
[("", 'a', "bcd"), ("a", 'b', "cd"), ("ba", 'c', "d"), ("cba", 'd', "")]
Once you have that, you can simply repeatedly non-deterministically choose an element from the ever-shrinking list of available options, making a pair after every other choice.
We can make use of a helper function pick that returns a list of 2-tuples with as first element the item picked, and a second element a list of remaining elements:
pick :: [a] -> [(a, [a])]
pick [] = []
pick (x:xs) = (x, xs) : …
where the … part should make a call to pick with the tail of the list, and prepend each second item of the 2-tuples returned with x.
With this pick function we can then construct all combinations with:
pairs :: [a] -> [[(a, a)]]
pairs [] = [[]]
pairs (x:xs) = [(x,y):tl | (y, zs) <- pick xs, tl <- pairs zs]

Getting the 2nd element of a list

I have a function with this type:
calculator :: [Float] -> [Int] -> Float
and I need:
Helper :: [String] -> [[Int]] -> [Float] -> [(String, Float)]
Following problem is given:
I just want to take every 2nd element of the [[Int]]
e.g.: I have an given Int [[1,0], [2,0], [3,0]].
I want to get the first element of each list in a list to put it into my calculator.
My idea was to concat the list of [Int].
e.g.:
[[1,0], [2,0], [3,0]].
concat [[1,0], [2,0], [3,0]] => [1,0,2,0,3,0]
I want this without the "0" values, due this is an indice which i dont need.
How can i remove every 2nd value in a list?
Is that possible with a higher order function?
The thinking goes like this: first, an empty list with every second value removed would be an empty list. Let's write that down:
withoutEverySecondValue [] = []
Now, if a list that consists of two values x and y, and then some tail xs, then to remove every second value from such list would mean (1) ignore y, (2) remove every second value from the tail xs, and (3) prepend x to the result of that. Let's write that down:
withoutEverySecondValue (x:y:xs) = x : withoutEverySecondValue xs
And that's it! Just add a type signature, and you're done!
withoutEverySecondValue :: [a] -> [a]
withoutEverySecondValue [] = []
withoutEverySecondValue (x:y:xs) = x : withoutEverySecondValue xs
There's one thing missing here though: what if a list is not empty, but also doesn't have two elements x and y? What should the result be then? I'll leave determining and writing that down as an exercise.
This function will give you all but the 2nd element of a list:
allBut2nd :: [a] -> [a]
allBut2nd [] = []
allBut2nd list = head list : tail (tail list)

Haskell mix two lists

Im about to write my first haskell program, so I need your help. I want to interlink two lists. For example;
a = [4,8,20]
b = [3,5,17,56,89,30]
interlink a b = [4,3,8,5,20,17,56,89,30]
The resulting list must cointain the elements of List a and b alternately. If one List is longer then the elements of the longer list should be added to the result list after the shorter list mashed up with the elements of the longer list. I think you saw that in my example above.
Now how do i do this in Haskell??
My start
mix :: [a]->[a]->[a]
mix (x:l1) (y:l2) = (x:y:[])
mix [] [] = []
Please, can you help me??
I do not have an interpreter available to use as I am on a different computer to usual, but here is some code:
mix :: [a] -> [a] -> [a]
mix (x:xs) (y:ys) = x : y : mix xs ys
mix x [] = x
mix [] y = y
Edit: I just tested this online, I believe it works.
So there are two functions transpose and concat.
-- transpose :: [[a]] -> [[a]]
-- concat :: Foldable t => t [a] -> [a]
Since List already has an instance of Foldable this ends up being one line of code like so:
concat . transpose $ a : b : []
or
concat . transpose $ [a,b]
The first step is to create a list of lists with transpose like so
λ> transpose $ [a, b]
[[4,3],[8,5],[20,17],[56],[89],[30]]
which we then collapse into one.
The secret here is to use function composition. The . is a function that takes two functions and calls one after the other creating a larger function so:
(.) :: (b -> c) -> (a -> b) -> a -> c
means: take the result of the first function, transpose, and feed it to the next one, concat.
We can chain as many functions as we wish as long as the types allow it.
In our case the composition creates a function [a] -> [a] -> [a]

Resources