Identifying duplicates in Haskell tuples - algorithm

I'm trying to write a function that will Nothing a Just Int tuple if any two values in the tuple are the same. For a tuple of five values, here's what I've got. Clearly, there's room for improvement:
nothingIfMatch :: Maybe (Int, Int, Int, Int, Int) -> Maybe (Int, Int, Int, Int, Int)
nothingIfMatch Nothing = Nothing
nothingIfMatch (Just (a, b, c, d, e))
| a == b = Nothing
| a == c = Nothing
| a == d = Nothing
| a == e = Nothing
| b == c = Nothing
| b == d = Nothing
| b == e = Nothing
| c == d = Nothing
| c == e = Nothing
| d == e = Nothing
| otherwise = Just (a, b, c, d, e)
Considering there are "n choose 2" possible intersections for an n-tuple, in this case, there are only 10 options. But imagine this were an 8-tuple, with 28 possibilities, or a 10-tuple, with 45.
There has to be a more idiomatic way to do this, probably relying on non-determinism features.
How should this be done?

We can first produce a list of Ints and then perform all equality checks:
import Data.List(tails)
twoEqual :: Eq a => [a] -> Bool
twoEqual xs = any (uncurry elem) [(h, t) | (h:t) <- tails xs]
Here we first generate for every element in the list a tuple containing the element and the rest of the list. Then we perform elem functions: we call elem on the item and the rest of the list and in case any of these checks holds, then we return True, False otherwise.
So now we can construct a list from this tuple and then use a guard to perform the checks:
nothingIfMatch :: Eq a => Maybe (a, a, a, a, a) -> Maybe (a, a, a, a, a)
nothingIfMatch = (>>= f)
where f r#(a, b, c, d, e) | twoEqual [a, b, c, d, e] = Nothing
| otherwise = Just r
We can easily add one extra element to the tuple and add it to the list in the twoEqual call. Here we still perform O(n2). We can do it in O(n log n) if we can order the elements first, or we can even do it in O(n) in case the elements are hashable and no hash collisions occur.
For example:
-- O(n log n) if the elements can be ordered
import Data.List(sort, tails)
twoEqual :: Ord a => [a] -> Bool
twoEqual xs = or [h1 == h2 | (h1:h2:_) <- tails (sort xs)]
Or in case the elements can be hashed:
-- O(n) in case the elements are hashable and no hash collisions
import Data.Hashable(Hashable)
import Data.HashSet(fromList, member)
twoEqual :: (Hashable a, Ord a) => [a] -> Bool
twoEqual xs = any (flip member hs) xs
where hs = fromList xs

Related

Sorting a list of ('String', int) by its int (Haskell)

I am brand new to Haskell, so I'm still learning a lot of things. I was given a list of name and age, and I need to sort them in both alphabetical order and in increasing order using their age. I managed to sort the list alphabetically, but I'm unsure how to do it using its age values. What can I change in the code below? Thank you for your help.
qsort :: (Ord a) => [a] -> [a]
-- check to see if the list is empty
qsort [] = []
qsort [x] = [x] -- Single element list is always sorted
qsort [x, y] = [(min x y), (max x y)]
-- x is the pivot, left quicksort returns smaller sorted and right quicksort bigger sorted
qsort (x:xs) =
qsort [a | a <- xs, a <= x] ++ [x] ++ qsort [a | a <- xs, a > x]
people=[("Steve",20),("Smith",31),("Kris",19),("Beth",21)]
main = do
print(qsort people) -- sort alphabetically
First, let's simplify your function a bit. Both the [x] and [x, y] cases are redundant: they are completely captured by the (x:xs) case. So let's remove those.
qsort :: (Ord a) => [a] -> [a]
qsort [] = []
qsort (x:xs) =
qsort [a | a <- xs, a <= x] ++ [x] ++ qsort [a | a <- xs, a > x]
Now, currently we assume that the type of our list and the type we're sorting by are the same. We call them both a. Let's instead have two types: a will be the type of our list and b will be the type we want to sort by. Only b has to satisfy Ord, and we'll need a function to convert an a into a b so we can sort our list. This is our desired type
qsort :: (Ord b) => (a -> b) -> [a] -> [a]
Our base case is basically the same, except that we ignore the function argument.
qsort _ [] = []
In our recursive case, we compare by applying the function f :: a -> b and then using <= or >.
qsort f (x:xs) =
qsort f [a | a <- xs, f a <= f x] ++ [x] ++ qsort f [a | a <- xs, f a > f x]
Now we can sort by whatever Ord type we want. We can sort by the first element of a tuple
-- Note: (fst :: (a, b) -> a) is in Prelude
print (qsort fst people)
or the second
-- Note: (snd :: (a, b) -> b) is in Prelude
print (qsort snd people)
both by their natural sorting order.
If we want to sort in the opposite order (descending rather than ascending), we can use Down as our function. If we want to sort by some complex order, we can always use the newtype pattern.

Error with using sort on type a in Haskell

I am pretty new to Haskell and I am trying to write a function neighbours :: Int -> Metric a -> Point a -> [Point a] -> [Point a] such that neighbours k d p xs returns a list of the k nearest neighbours, in distance order, according to metric d to point p in the list xs of points. My code is
type Point a = (a, a)
type Metric a = Point a -> Point a -> Double
type Tuple a = (Double, Point a)
create:: Metric a -> Point a -> [Point a] -> [Tuple a] -> [Tuple a]
create d p (x:xs) ys | length xs == 0 = sort(((d p x), x) : ys)
| otherwise = create d p xs (((d p x), x) : ys)
takeP:: Tuple a -> Point a
takeP (_,p) = p
pList:: [Tuple a] ->[Point a]-> [Point a]
pList (x:xs) ys | length xs == 0 = reverse (takeP x : ys)
| otherwise = pList xs (takeP x : ys)
neighbours :: Int -> Metric a -> Point a -> [Point a] -> [Point a]--
neighbours k d p xs = take k (pList (create d p xs []) [])
But I am getting an error on sort which is:
* No instance for (Ord a) arising from a use of `sort'
Possible fix:
add (Ord a) to the context of
the type signature for:
create :: forall a.
Metric a -> Point a -> [Point a] -> [Tuple a] -> [Tuple a]
* In the expression: sort (((d p x), x) : ys)
In an equation for `create':
create d p (x : xs) ys
| length xs == 0 = sort (((d p x), x) : ys)
| otherwise = create d p xs (((d p x), x) : ys)
I used type Point a = (Int, Int) at first and it was working fine but in the specification it is required that Point is type Point a = (a, a) which caused my error. The other problem is that I cannot change the function types so I can't just add (Ord a) as proposed.
Is there a way to sort the Tuples' list by the first variable without encountering errors?
In your create function, you make use of sort :: Ord a => [a] -> [a]:
… = sort (((d p x), x) : ys)
this thus means that type of objects that we are sorting, in this case Tuple a, needs to be an instance of the Ord typeclass. A 2-tuple is an instance of the Ord typeclass, if both the type of the items are instances of Ord as well, so in this case Double and Point a. Since Point a is also a 2-tuple, but of two as, this thus means that Tuple a is an instance of Ord, if a is an instance of Ord. You thus should add a type constraint:
create :: Ord a => Metric a -> Point a -> [Point a] -> [Tuple a] -> [Tuple a]
create d p (x:xs) ys | length xs == 0 = sort(((d p x), x) : ys)
| otherwise = create d p xs (((d p x), x) : ys)
The create function makes use of some anti-patterns like using length, which takes linear time. You can in fact rewrite this to sorting a mapping:
create :: Ord a => Metric a -> Point a -> [Point a] -> [Tuple a]
create d p = sort . map f
where f x = (d p x, x)
This removes the ys parameter, which here only seems to be used as a accumulator.
If you wish to only sort on the first item of the 2-tuple, you can make use of sortOn :: Ord b => (a -> b) -> [a] -> [a]:
create :: Metric a -> Point a -> [Point a] -> [Tuple a]
create d p = sortOn fst . map f
where f x = (d p x, x)

SML merge_sort function using let in and pattern matching

fun merge_sort (_, nil) = nil
| merge_sort (_, [a]) = [a]
| merge_sort (f, L) =
let
fun halve nil = (nil,nil)
| halve [a] = ([a], nil)
| halve (a :: b :: rest) =
let
val (x , y) = halve rest
in
(a :: x, b :: y)
end
fun merge (f, nil, x) = x
| merge (f, x, nil) = x
| merge (f, a::b, x::y) =
if f(a, b) then a :: merge (f, b, x::y)
else x :: merge (f, a::b, y);
val (x, y) = halve L
in
merge(f, merge_sort(f, x), merge_sort(f,y))
end;
merge_sort (op <) [2,1,3,2,4,3,45];
This is a SML function that I have been working on. It is meant to take a function call as shown in the bottom and merge sort. Must be one function. I am struggling understanding the pattern matching and how to fully make this function work.
I get this error code when I compile and run it.
$sml < main.sml
Standard ML of New Jersey v110.78 [built: Thu Aug 31 03:45:42 2017]
- val merge_sort = fn : ('a * 'a list -> bool) * 'a list -> 'a list
stdIn:23.1-23.35 Error: operator and operand don't agree [tycon mismatch]
operator domain: ('Z * 'Z list -> bool) * 'Z list
operand: [< ty] * [< ty] -> bool
in expression:
merge_sort <
-
I don't entirely know what I am doing wrong
Using the convention of naming lists with a plural "s" and using the same base name for the head and tail in patterns makes the problem stick out immediately:
merge (f, x::xs, y::ys) =
if f(x, xs) then x :: merge (f, xs, y::ys)
else y :: merge (f, x::xs, ys);
where f(x, xs) should of course be f(x, y).
This convention is conventional because it's useful. Don't leave home without it.
You have a typo; this:
if f(a, b) then a :: merge (f, b, x::y)
else x :: merge (f, a::b, y);
should be this:
if f (a, x) then a :: merge (f, b, x::y)
else x :: merge (f, a::b, y)
(calling f on (a, x) rather than on (a, b)).
Since b and x have different types ('Z list and 'Z, respectively), the consequence of this typo is that f is inferred to have the wrong type ('Z * 'Z list -> bool rather than 'Z * 'Z -> bool), so the whole merge_sort function is inferred to have the wrong type scheme (('a * 'a list -> bool) * 'a list -> 'a list instead of ('a * 'a -> bool) * 'a list -> 'a list).
Some explicit type annotations (e.g. writing f : 'a * 'a -> bool in one place) might make it easier for the compiler to help you see where you're deviating from the types you intended; but, admittedly, if you don't already know where you're deviating, then it can be hard to figure out where to add annotations so the compiler can help you find where you're deviating.

Haskell: f n that returns list of lists of n elements from [1..n]

I need a function f :: (Integral n) => n -> [[n]].
The returned list should contain all lists of length n where all elements originate from [1..n].
Example:
f 2 = [[1,1],[1,2],[2,1],[2,2]]
This is an easy problem for constant ns:
f2 = [[a, b] | a <- [1..2], b <- [1..2]]
f3 = [[a, b, c] | a <- [1..3], b <- [1..3], c <- [1..3]]
f4 = [[a, b, c, d] | a <- [1..4], b <- [1..4], c <- [1..4], d <- [1..4]]
one solution can be
f n = sequence . replicate n $ [1..n]
Note that f 10 will have 10^10 elements
Another method could be:
Prelude> import Control.Monad
Prelude Control.Monad> f n = replicateM n [1..n]
Prelude Control.Monad> f 2
[[1,1],[1,2],[2,1],[2,2]]
A solution with the great combinat library:
Math.Combinat.Sets> combine 3 [1 .. 3]
[[1,1,1],[1,1,2],[1,1,3],[1,2,2],[1,2,3],[1,3,3],[2,2,2],[2,2,3],[2,3,3],[3,3,3]]

Algorithm for grouping many singly linked lists

I have a data set that consists of objects with the form:
A -> Some parent (E.g. A -> null)
B -> Some parent (E.g. B -> D)
C -> Some parent (E.g. C -> A)
D -> Some parent (E.g. D -> null)
E -> Some parent (E.g. E -> A)
F -> Some parent (E.g. F -> G)
G -> Some parent (E.g. G -> D)
H -> Some parent (E.g. H -> C)
I -> Some parent (E.g. I -> G)
J -> Some parent (E.g. J -> null)
I want all the grouped linked lists, something like the following:
A <- C <- H
^-E
J
D <- B
^- G <- F
^- I
Is there a general algorithm to solve the problem of grouping the singly-linked lists that will perform better than pure brute force?
The use case for me here is that, given G, how can I get:
D <- B
^- G <- F
^- I
in an efficient way.
Construct an array of 2-element structures, in which the first element is the destination and the second is the source:
(null, A),
( D, B),
( A, C),
(null, D),
( A, E),
( G, F),
( D, G),
( C, H),
( G, I),
(null, J)
Sort this array by the first element:
(null, A),
(null, D),
(null, J),
( A, C),
( A, E),
( C, H),
( D, B),
( D, G),
( G, F),
( G, I)
And then recursively reveal the whole graph, using the initial data and the array just created:
a.
^- G
b.
^- G <- F
^- I
c. D
^- G <- F
^- I
d. D <- B
^- G <- F
^- I

Resources