Grouping lists by common elements - c++

I'm looking for a clever/fast C++ algorithm, which would allow me to do grouping of several lists of objects when they contain common objects inside. Let's say I have N lists, each containing 1..M objects (O) associated with one element E:
[O1, O2] -> E1
[O3] -> E2
[O1, O4, O5] -> E3
[O2, O5] -> E4
[O3, O6] -> E5
I wish to rearrange them into the following:
[O1, O2, O4, O5] -> [E1, E3, E4]
[O3, O6] -> [E2, E5]
The result has all common objects grouped together with all associated elements. No object is shared in the end between lists.

For each object, calculate which elements contain it.
i.e.
01 -> [E1, E3]
02 -> [E4]
03 -> [E2, E5]
04 -> [E3]
05 -> [E3, E4]
06 -> [E5]
These lists induce a graph: there's a vertex per element, and two vertices are connected if the corresponding elements show up in the same list.
It seems to me that what you want to calculate are the connected components of the graph.

Related

How do I map each value from one list to another? (Haskell)

This is the code I have so far:
data Suit = Diamond | Club | Heart | Spade
deriving (Read, Enum, Eq, Bounded)
data Rank = Two | Three | Four
| Five | Six | Seven | Eight | Nine | Ten
| Jack | Queen | King | Ace
deriving (Read, Enum, Eq, Ord, Bounded)
and I am trying to map each value, either Rank or Suit to a unique prime number.
primeMapper :: Either Rank Suit -> Int
should be the final function and I want to iterate over each Suit and set it to the first four primes:
primeMapper [Diamond .. Spade] = [2,3,5,7]
and each Rank equal to the rest of the primes up until the 17th:
primeMapper [Two .. Ace] = drop 4 . take 17 $ primes
assuming I have a generating function called primes.
This code, however throws errors obviously because it generates a list from a list. How can I achieve what I am trying to do? Let me know if I can explain it better.
The ultimate goal is to have a hash table that gives unique IDs to each cards based on prime factors, and then generate prime factorization and use modulo to quickly compare poker hands.
Ultimately I solved what I am trying to do by hand as so:
primeMapper :: Either Suit Rank -> Int
primeMapper x = case x of
Left Diamond -> 2
Left Club -> 3
Left Heart -> 5
Left Spade -> 7
Right Two -> 11
Right Three -> 13
Right Four -> 17
Right Five -> 19
Right Six -> 23
Right Seven -> 29
Right Eight -> 31
Right Nine -> 37
Right Ten -> 41
Right Jack -> 43
Right Queen -> 47
Right King -> 53
Right Ace -> 59
... was there a more concise way to do this rather than write each case out by hand?
Your solution using pattern matching is best, though I would prefer
primeMapper :: Either Suit Rank -> Int
primeMapper (Left Diamond) = 2
primeMapper (Left Club) = 3
...
rather than your long case expression.
However you could also use lookup :: Eq a => a -> [(a, b)] -> Maybe b
import Data.Maybe (fromJust)
primeMapper :: Either Suit Rank -> Int
primeMapper = fromJust . flip lookup zippedPrimes
where
zippedPrimes = zip suitranks primes
suitranks = fmap Left suits ++ fmap Right ranks :: [Either Suit Rank]
suits = fromEnum minBound
ranks = fromEnum minBound
Depending on what you plan to use this for, you may not need to use primes or prime factorizations at all; you can get fast conversion to and from plain numbers just by picking one or the other of the suit or rank for a base conversion. Here I'll pick suit -- there are four suits, so take the first digit in base 4 as the suit and the remaining digits as the rank.
encode :: (Suit, Rank) -> Int
encode (s, r) = fromEnum s + 4 * fromEnum r
decode :: Int -> (Suit, Rank)
decode n = (toEnum s, toEnum r) where (r, s) = n `quotRem` 4
You can verify in ghci that this gives a unique number to each card:
> [encode (s, r) | r <- [minBound .. maxBound], s <- [minBound .. maxBound]]
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51]
And that they decode appropriately:
> map decode [0..51] == [(s, r) | r <- [minBound .. maxBound], s <- [minBound .. maxBound]]
True
You can adapt some of this I hope.
no2s3s5s = \n -> take n $ scanl (\b a -> a+b) 11 $ cycle [2,4,2,4,6,2,6,4]
rnk = filter (/=49) $ no2s3s5s 14
stv = [2,3,5,7]
_deck = [ b*v | b <- stv, v <- rnk]
_Dia = take 13.drop (0*13) $ _deck
_Clb = take 13.drop (1*13) $ _deck
_Hrt = take 13.drop (2*13) $ _deck
_Spd = take 13.drop (3*13) $ _deck
_Dia
[22,26,34,38,46,58,62,74,82,86,94,106,118]
_Clb
[33,39,51,57,69,87,93,111,123,129,141,159,177]
_Hrt
[55,65,85,95,115,145,155,185,205,215,235,265,295]
_Spd
[77,91,119,133,161,203,217,259,287,301,329,371,413]
_deck
[22,26,34,38,46,58,62,74,82,86,94,106,118,33,39,51,57,69,87,93,111,123,129,141,159,177,55,65,85,95,115,145,155,185,205,215,235,265,295,77,91,119,133,161,203,217,259,287,301,329,371,413]
length _deck
52
Your multiples (_deck) are all unique.
I normally use no2s3s5s with a computed (limited) factor list and the mod function to generate a long prime list.

How get limited number of input in Haskell

I am a newbie in Haskell.
Let says my program want to calculate something from this pattern of input:
a1 b1 c1
a2 b2 c2
...
16 b6 c6
The input contains 6 lines and each line has 3 numbers
I want to get data as [(Integer, Integer, Integer)] but limit the length of the list to be only 6 before going to the calculation.
How could I do this? Also, how could I get a length from [(Integer, Integer, Integer)]
Thank you for your help
There are three steps to this:
Read 6 lines
Break each line into the (hopefully three) parts
Convert to the desired result
Some sample code is below:
input = do
lines <- sequence $ take 6 $ repeat readLn
let table = words <$> lines
return [(a, b, c) | [a,b,c] <- table]
This gives input :: IO [(String, String, String)] but I'm sure you could modify this to give you what you want.

replacing each element of a list by a specific list

I try to define replaceEltByclass(E1:list,E2:list) E is a list without sublist. each element of E1 belonging to a class C is replaced by the
elements of C. The final result is put in E2. For example, the goal rep_class([e1,e4,e6,e11], E2) will provide the list E2 : [[e1,e8,e10], e4,[e3,e6,e7],e11]. I don't have the good results.
/*The code*/
/*facts*/
class(c1,[e3, e6, e7]).
class(c2,[e1, e8, e10]).
/*rules*/
rep_class([],[]).
rep_class([E|Q],E2) :-
class(C,L),
not(member(E,L)),
concat(E2,E,E2),
rep_class(Q,E2).
rep_class([E|Q],E2) :-
class(C,L),
member(E,L),
concat(E2,L,E2),
rep_class(Q,E2).
/*conventional concat*/
concat([],L,L).
concat([H|T],L,[H|Res]) :- concat(T,L,Res).
The problem is in: class(C,L),not(member(E,L)), because it will give two solution one if C=C2 and then for example e1 belongs in C2 so it will replace it with L and one solution when C=C1 where it will leave it as e1. You need to write "does C exists such member(e1,L)??" so you have to collect all possible lists and see if member(e1,L) stands for a list L. So with some changes my version is :
class(c1,[e3, e6, e7]).
class(c2,[e1, e8, e10]).
rep_class([],[]).
rep_class([E|Q],[E|E2]) :-
findall(L,class(_,L),List),
not(find(List,E,_)),
rep_class(Q,E2).
rep_class([E|Q],[Lout|E2]) :-
findall(L,class(_,L),List),
find(List,E,Lout),
rep_class(Q,E2).
find([Lin|_],E,Lin):-member(E,Lin).
find([Lin|T],E,Lout):-not(member(E,Lin)),find(T,E,Lout).
As an example:
?- rep_class([e1,e4,e6,e11], E2).
E2 = [[e1, e8, e10], e4, [e3, e6, e7], e11] ;
false.

Decrementing ranges in Haskell

I am very new to Haskell. Could someone please explain why defining a list like this returns an null list
ghci> let myList = [10..1]
ghci> myList
[]
However this works correctly.
ghci> let myList = [10, 9..1]
ghci> myList
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Basically, because [10..1] is translated to enumFromTo 10 1 which itself has the semantics to create a list by taking all elements less-than 1 which result from counting upward (with step-size +1) from (including) 10.
Whereas [10, 9..1] is translated to enumFromToThen 10 9 1 which explicitly states the counting step-size as 9-10, i.e. -1 (which is hard-coded to +1 for enumFromTo)
A more accurate specification can be found in the Haskell Report (6.3.4 The Enum Class):
enumFrom :: a -> [a] -- [n..]
enumFromThen :: a -> a -> [a] -- [n,n'..]
enumFromTo :: a -> a -> [a] -- [n..m]
enumFromThenTo :: a -> a -> a -> [a] -- [n,n'..m]
For the types Int and Integer, the enumeration functions have the following meaning:
The sequence enumFrom e1 is the list [e1,e1+1,e1+2,...].
The sequence enumFromThen e1 e2 is the list [e1,e1+i,e1+2i,...], where the increment, i, is e2-e1. The increment may be zero or negative. If the increment is zero, all the list elements are the same.
The sequence enumFromTo e1 e3 is the list [e1,e1+1,e1+2,...e3]. The list is empty if e1 > e3.
The sequence enumFromThenTo e1 e2 e3 is the list [e1,e1+i,e1+2i,...e3], where the increment, i, is e2-e1. If the increment is positive or zero, the list terminates when the next element would be greater than e3; the list is empty if e1 > e3. If the increment is negative, the list terminates when the next element would be less than e3; the list is empty if e1 < e3.
Arithmetic sequence notation is just syntactic sugar for functions from the Enum class.
[a..] = enumFrom a
[a..b] = enumFromTo a b
[a, b..] = enumFromThen a b
[a, b..c] = enumFromThenTo a b c
As for why they weren't defined to automatically reverse, I can only speculate but here are some possible reasons:
If a and b are defined elsewhere, it would be harder to tell at a glance in which direction [a..b] would go.
It has nicer mathematical properties to reason about. You don't have to add special cases for when the sequence would be reversed.
If you want to generate a list from a to b regardless of whether a < b, you can use the following:
[a, a + (signum $ b - a)..b]
For newbies.
To make a list with all the numbers from 20 to 1, you can't just do
[20..1]
you have to specify as such:
[20,19..1]

Filtering directly and indirectly connected things from list

if you have a function "test a b" which returns true if a and b are connected directly and if you have a given unordered list of things, what would be an elegant and fast solution to filter all connected things from given list?
Example:
let test a b = let diff = a - b in diff == 0 ;;
let lst = [4;1;7;3;8;9;2;0] ;;
filter_connected 2 lst ;;
-> [4;1;3;2;0]
Any hints?
Hmmm, I will try to refine my question...
there exists an unsorted list of things, pE. "let lst = [a;b;c;d;e;f;g;h];;" with type
val a' list
there exists also a function which decide if two things are directly connectable or in other words, if the two things are direct neighbours:
val test : a' -> a' -> bool
what I need is a function which has three arguments, the first one is a specific thing, the second one the unsorted list of things as suggested above, the last one is the test-function described above:
val filter_connected : a' -> a' list -> (a' -> a' -> bool) -> a' list
if a <-> b are direct neigbours and b <-> c are direct neighbours then [a;b;c] are connected.
The suggested "List.filter () lst" does not help here, because it only filters the directed neighbours.
In the example above with a <-> b and b <-> c as direct neighbours in case of test-function, and all others not, the "filter_connected" call will be:
"filter_connected b lst (test);;"
and would return:
[a;b;c]
Hope it will be more clean...
I will assume that you want to get the elements of the original list that are at distance less than 2 from 2.
Objective Caml version 3.11.1
# let test x = abs (x - 2) <= 2 ;;
val test : int -> bool = <fun>
# List.filter test [4;1;7;3;8;9;2;0] ;;
- : int list = [4; 1; 3; 2; 0]
#
List.filter is a function from the standard library. List.filter f l produces the list of elements of l for which f answers true.
Getting the function that decides if each element should go in the results list is orthogonal to the problem of filtering the list once you have this function, so you should do that first.
If you wish to use for f a function that is the transitive closure of a relation that you have, you can use the library ocamlgraph to obtain that transitive closure. Specifically, of these functions, use add_vertex for each puzzle piece, add_edge for each relation that you have, and then apply function transitive_closure to get a new graph g in which you can ask if there is an edge between two elements e1 and e2 with mem_edge g e1 e2. The partially applied function mem_edge g e1 can be passed to List.filter.