Declaratieve Talen/oplossingAlternatieveOrdes: verschil tussen versies

Uit Wina Examenwiki
Naar navigatie springen Naar zoeken springen
Peter.roelants (overleg | bijdragen)
Geen bewerkingssamenvatting
Geen bewerkingssamenvatting
 
(4 tussenliggende versies door 2 gebruikers niet weergegeven)
Regel 1: Regel 1:
==== Een volledige oplossing ====
<pre>
import Data.List
import Data.Maybe
type Symbool a = a
type Woord a = [Symbool a]
type Orde a = [Symbool a]
data NogVrij a = NogVrij (Symbool a) (Symbool a) deriving (Show)
-- Bereken de orde van een alfabet, gegeven een reeks alfabetisch gesorteerd woorden.
berekenOrde :: (Eq a) => [Woord a] -> [Orde a]
berekenOrde woorden =
  berekenOrde' (alleSymbolen woorden)
  where berekenOrde' [] = [[]]
        berekenOrde' todo = [s:rest | s <- todo, all (\s2 -> heeftKleinereOrde s s2 (ordes [woorden])) (delete s todo), rest <- berekenOrde' (delete s todo)]
-- Geef alle symbolen die voorkomen in een reeks woorden. 
alleSymbolen :: (Eq a) => [Woord a] -> [Symbool a]
alleSymbolen woorden = nub $ concat woorden
-- Return True als Symbool1 een kleinere orde heeft dan Symbool2.
-- Return ook True wanneer de orde van Symbool1 tov Symbool2 onbepaald is.
heeftKleinereOrde :: (Eq a) => Symbool a -> Symbool a -> [Orde a] -> Bool
heeftKleinereOrde s1 s2 ordes =
  all (\w -> isNothing (positie s1 w) || isNothing (positie s2 w) || fromJust (positie s1 w) < fromJust (positie s2 w)) (ordes)
  where positie s woord = elemIndex s woord
-- Bereken alle ordes die afgeleid kunnen worden uit een reeks alfabetisch gesorteerd woorden.
-- We steken eerst het eerst symbool van elk woord in een lijst, vervolgens werken we recursief
-- verder met de woorden waarvan het eerste symbool gelijk was ...
ordes :: (Eq a) => [[Woord a]] -> [Orde a]
ordes [] = []     
ordes (wl:wls) = (lijstMetEersteSymbolen wl : ordes (map verwijderEersteSymbool (groepeerOpEersteSymbool wl))) ++ ordes wls
-- Steek het eerste symbool van elk woord in een lijst.
lijstMetEersteSymbolen :: (Eq a) => [Woord a] -> [Symbool a]
lijstMetEersteSymbolen woorden = nub $ map (!!0) woorden
-- Verwijder het eerste symbool van elk woord.
verwijderEersteSymbool :: (Eq a) => [Woord a] -> [Woord a]   
verwijderEersteSymbool [] = []
verwijderEersteSymbool ((_:rest):xs)
  | rest == []  = verwijderEersteSymbool xs
  | otherwise  = rest : verwijderEersteSymbool xs
 
-- Maak sublijsten waarbij elke sublijst woorden bevat met hetzelfde beginsymbool. 
groepeerOpEersteSymbool :: (Eq a) => [Woord a] -> [[Woord a]]
groepeerOpEersteSymbool woorden2 = groupBy (\x y -> x!!0 == y!!0) woorden2
-- Detecteer uitgaande van 2 mogelijke ordes wat de vrijheidsgraden nog zijn.
maakUniek :: (Eq a, Ord a) => Orde a -> Orde a -> [NogVrij a]
maakUniek o1 o2 = [NogVrij s1 s2 | s1 <- o1, s2 <- o1, s1 < s2, not (dezelfdeOrde s1 s2) ]
  where dezelfdeOrde s1 s2 
          | heeftKleinereOrde s1 s2 [o1] = heeftKleinereOrde s1 s2 [o2]
          | otherwise = heeftKleinereOrde s2 s1 [o2]
</pre>
--[[Gebruiker:Pieter|Pieter]] 13 jan 2014 19:55 (UTC)
====Een oplossing====
====Een oplossing====
Een oplossing voor het eerste deel van de opgave. Het is een beetje Prolog-generate-and-test geïnspireerd.
Een oplossing voor het eerste deel van de opgave. Het is een beetje Prolog-generate-and-test geïnspireerd.
Regel 52: Regel 113:


====Een gedeeltelijke oplossing ====
====Een gedeeltelijke oplossing ====
<pre>


<nowiki>
{-
Hieronder volgt een gedeeltelijke oplossing ('maakuniek' is niet geïmplementeerd)
Hieronder volgt een gedeeltelijke oplossing ('maakuniek' is niet geïmplementeerd)
Het idee is dat de woorden als een soort van 'Boom' geparsed gaan worden:
Het idee is dat de woorden als een soort van 'Boom' geparsed gaan worden:
Regel 70: Regel 129:
Dus de orderingen zijn: (a < b < c) en ( a < d) en (d < c)
Dus de orderingen zijn: (a < b < c) en ( a < d) en (d < c)
=>(a<b<d<c) of (a<d<b<c)
=>(a<b<d<c) of (a<d<b<c)
-}
 


import List
import List
Regel 120: Regel 179:
permutations [] = [[]]
permutations [] = [[]]
permutations xs = [ x:ys | x <- xs, ys <- permutations (delete x xs)]
permutations xs = [ x:ys | x <- xs, ys <- permutations (delete x xs)]
</pre>
--
Nog één.. (enkel voor 1e deel)
<pre>
import List
berekenorde::[String]->[String]
berekenorde list = [ alphabet | alphabet<-(perm (allChars list)), volgorde alphabet list]
allChars::[String]->[Char]
allChars [] = []
allChars (list) = verwijderdubbel (concat list)
where verwijderdubbel [] = []
verwijderdubbel (x:xs)
| elem x xs = verwijderdubbel $ x:(delete x xs)
| otherwise = x:(verwijderdubbel xs)
-- permutatie
perm::[Char]->[String]
perm [] = [[]]
perm list = [x:ys| x<-list, ys<-perm (delete x list)]
-- voldoet de String aan de volgorde opgelegd door de list van strings?
-- (mogelijk alphabet)->(lijst woorden)->(correct alphabet?)
volgorde::String->[String]->Bool
volgorde _ [_] = True
volgorde a (x:y:xs)
| rangschikking a x y = volgorde a (y:xs)
| otherwise = False
--2 opeenvolgende woorden vergelijken met elkaar geeft uitsluitsel!
-- (mogelijk alphabet)->(woord 1)->(woord 2)->(correct alphabet?)
rangschikking::String->String->String->Bool
rangschikking _ [] _ = True
rangschikking _ _ [] = False
rangschikking (a:as) (v:vs) (w:ws)
| v == w = rangschikking (a:as) vs ws
| a == w = False
| a == v = True
| otherwise = rangschikking as (v:vs) (w:ws)
</pre>


</nowiki>
--[[Gebruiker:Andries|Andries]] 17 jan 2012

Huidige versie van 13 jan 2014 18:59

Een volledige oplossing

import Data.List
import Data.Maybe

type Symbool a = a
type Woord a = [Symbool a]
type Orde a = [Symbool a]
data NogVrij a = NogVrij (Symbool a) (Symbool a) deriving (Show)

-- Bereken de orde van een alfabet, gegeven een reeks alfabetisch gesorteerd woorden.
berekenOrde :: (Eq a) => [Woord a] -> [Orde a]
berekenOrde woorden = 
  berekenOrde' (alleSymbolen woorden)
  where berekenOrde' [] = [[]]
        berekenOrde' todo = [s:rest | s <- todo, all (\s2 -> heeftKleinereOrde s s2 (ordes [woorden])) (delete s todo), rest <- berekenOrde' (delete s todo)]

-- Geef alle symbolen die voorkomen in een reeks woorden.   
alleSymbolen :: (Eq a) => [Woord a] -> [Symbool a]
alleSymbolen woorden = nub $ concat woorden

-- Return True als Symbool1 een kleinere orde heeft dan Symbool2. 
-- Return ook True wanneer de orde van Symbool1 tov Symbool2 onbepaald is.
heeftKleinereOrde :: (Eq a) => Symbool a -> Symbool a -> [Orde a] -> Bool
heeftKleinereOrde s1 s2 ordes = 
  all (\w -> isNothing (positie s1 w) || isNothing (positie s2 w) || fromJust (positie s1 w) < fromJust (positie s2 w)) (ordes)
  where positie s woord = elemIndex s woord

-- Bereken alle ordes die afgeleid kunnen worden uit een reeks alfabetisch gesorteerd woorden.
-- We steken eerst het eerst symbool van elk woord in een lijst, vervolgens werken we recursief 
-- verder met de woorden waarvan het eerste symbool gelijk was ...
ordes :: (Eq a) => [[Woord a]] -> [Orde a]
ordes [] = []      
ordes (wl:wls) = (lijstMetEersteSymbolen wl : ordes (map verwijderEersteSymbool (groepeerOpEersteSymbool wl))) ++ ordes wls

-- Steek het eerste symbool van elk woord in een lijst.
lijstMetEersteSymbolen :: (Eq a) => [Woord a] -> [Symbool a]
lijstMetEersteSymbolen woorden = nub $ map (!!0) woorden

-- Verwijder het eerste symbool van elk woord.
verwijderEersteSymbool :: (Eq a) => [Woord a] -> [Woord a]     
verwijderEersteSymbool [] = []
verwijderEersteSymbool ((_:rest):xs)
  | rest == []  = verwijderEersteSymbool xs
  | otherwise   = rest : verwijderEersteSymbool xs
  
-- Maak sublijsten waarbij elke sublijst woorden bevat met hetzelfde beginsymbool.   
groepeerOpEersteSymbool :: (Eq a) => [Woord a] -> [[Woord a]]
groepeerOpEersteSymbool woorden2 = groupBy (\x y -> x!!0 == y!!0) woorden2

-- Detecteer uitgaande van 2 mogelijke ordes wat de vrijheidsgraden nog zijn.
maakUniek :: (Eq a, Ord a) => Orde a -> Orde a -> [NogVrij a]
maakUniek o1 o2 = [NogVrij s1 s2 | s1 <- o1, s2 <- o1, s1 < s2, not (dezelfdeOrde s1 s2) ]
  where dezelfdeOrde s1 s2  
          | heeftKleinereOrde s1 s2 [o1] = heeftKleinereOrde s1 s2 [o2] 
          | otherwise = heeftKleinereOrde s2 s1 [o2] 

--Pieter 13 jan 2014 19:55 (UTC)


Een oplossing

Een oplossing voor het eerste deel van de opgave. Het is een beetje Prolog-generate-and-test geïnspireerd.

 import List
 
 berekenorde::[String]->[String]
 berekenorde woorden = filter (correcteOrde paren) (permuteer letters)
 	where 
 		paren = woordenNaarParen woorden
 		letters = findLettersWoorden woorden
 
 woordenNaarParen::[String]->[(Char, Char)]
 woordenNaarParen list = nub $ woordenNaarParen' list
 woordenNaarParen' [] = []
 woordenNaarParen' (w:t) =
 	verwerkWoorden t w ++ woordenNaarParen t
 
 verwerkWoord::String->String->Maybe (Char, Char)
 verwerkWoord "" _ = Nothing
 verwerkWoord _ "" = Nothing
 verwerkWoord (c1:t1) (c2:t2)
 	| c1 /= c2 = Just (c1,c2)
 	| otherwise = verwerkWoord t1 t2
 
 -- geef woord en zoek naar paren met behulp van andere woordenlijst
 verwerkWoorden::[String]->String->[(Char, Char)]
 verwerkWoorden woorden woord = 
 	[ x | Just x <- map (verwerkWoord woord) woorden]	
 
 
 -- alle letters van alle woorden
 findLettersWoorden::[String]->[Char]
 findLettersWoorden lijst = 
 	nub $ concatenate lijst
 
 correcteOrde::[(Char,Char)]->[Char]->Bool
 correcteOrde [] letters = True
 correcteOrde ((c1,c2):t) letters = 
 	(elemIndex c1 letters) < (elemIndex c2 letters) && correcteOrde t letters
 
 permuteer::[a]->[[a]]
 permuteer [] = [[]]
 permuteer (h:t) = concatMap (permIns h) (permuteer t)
 permIns::a->[a]->[[a]]
 permIns x [] = [[x]]
 permIns x (h:t) = (x:h:t) : map (h:) (permIns x t)
 

--Roald 13 jan 2010 19:55 (UTC)


Een gedeeltelijke oplossing


Hieronder volgt een gedeeltelijke oplossing ('maakuniek' is niet geïmplementeerd)
Het idee is dat de woorden als een soort van 'Boom' geparsed gaan worden:
["ab", "abd", "abc", "ba", "bd", "cc"]
=>
[('a', ["b", "bd", "bc"]), ('b', ["a", "d"]), ('c', ["c"])]  -- (a < b < c)
=>
[('b', ["d", "c"])],
[('a', []), ('d', [])]   -- ( a < d)
[('c', [])]
=>
[('d', []), ('c', [])]   -- (d < c)
=>
Dus de orderingen zijn: (a < b < c) en ( a < d) en (d < c)
=>(a<b<d<c) of (a<d<b<c)


import List

alle_letters :: [String] -> [Char]
alle_letters woordenlijst = foldl union [] woordenlijst

-- vb.:
-- *Main> eerste_letters ["ab", "abd", "abc", "ba", "bd", "cc"]
-- [('a',"b"),('a',"bd"),('a',"bc"),('b',"a"),('b',"d"),('c',"c")]
eerste_letters :: [String] -> [(Char, String)]
eerste_letters xs = [((head x), (tail x)) | x <- (filter (/= []) xs)]

alle_eerste_letters :: [(Char, String)] -> [Char]
alle_eerste_letters lijst = nub [x | (x, s) <- lijst]

-- vb.:
-- *Main> groepeer ["ab", "abd", "abc", "ba", "bd", "cc"]
-- [('a',["b","bd","bc"]),('b',["a","d"]),('c',["c"])]
groepeer :: [String] -> [(Char, [String])]
groepeer xs = let eerste = (eerste_letters xs)
              in let letters = alle_eerste_letters eerste
                  in [ (l, [s | (c,s) <- eerste, c == l]) | l <- letters]
                  
-- vb.:
-- *Main> zoek_orde ["ab", "abd", "abc", "ba", "bd", "cc"]
-- [('a','b'),('d','c'),('a','d'),('b','c')]
zoek_orde :: [String] -> [(Char,Char)]
zoek_orde [] = []
zoek_orde woordenlijst = nub (zoek_orde_rec (groepeer woordenlijst))
                             
zoek_orde_rec :: [(Char, [String])] -> [(Char,Char)]
zoek_orde_rec [] = []
zoek_orde_rec [(c,rest)] = (zoek_orde rest)
zoek_orde_rec ((c1,rest1):(c2,rest2):cs) = ((c1,c2):(zoek_orde rest1)) ++ (zoek_orde rest2) ++ (zoek_orde_rec ((c2,rest2):cs))

berekenorde :: [String] -> [String]
berekenorde woordenlijst = let letters = alle_letters woordenlijst
                               orde = zoek_orde woordenlijst
                            in [ p | p <- (permutations letters), (correcte_ordening p orde)]

correcte_ordening :: String -> [(Char,Char)] -> Bool
correcte_ordening orde lijst = foldl (\a b -> (correcte_orde orde b) && a) True lijst
    
correcte_orde :: String -> (Char,Char) -> Bool
correcte_orde orde (c1,c2)= (findIndex (== c1) orde) < (findIndex (== c2) orde)

permutations :: Eq a => [a] -> [[a]]
permutations [] = [[]]
permutations xs = [ x:ys | x <- xs, ys <- permutations (delete x xs)]

--

Nog één.. (enkel voor 1e deel)


import List

berekenorde::[String]->[String]
berekenorde list = [ alphabet | alphabet<-(perm (allChars list)), volgorde alphabet list]

allChars::[String]->[Char]
allChars [] = []
allChars (list) = verwijderdubbel (concat list)
	where 	verwijderdubbel [] = []
		verwijderdubbel (x:xs) 
			| elem x xs	= verwijderdubbel $ x:(delete x xs)
			| otherwise	= x:(verwijderdubbel xs)

-- permutatie
perm::[Char]->[String]
perm [] = [[]]
perm list = [x:ys| x<-list, ys<-perm (delete x list)]

-- voldoet de String aan de volgorde opgelegd door de list van strings?
-- (mogelijk alphabet)->(lijst woorden)->(correct alphabet?)
volgorde::String->[String]->Bool
volgorde _ [_] = True
volgorde a (x:y:xs)
	| rangschikking a x y	= volgorde a (y:xs) 
	| otherwise		= False

--2 opeenvolgende woorden vergelijken met elkaar geeft uitsluitsel!
-- (mogelijk alphabet)->(woord 1)->(woord 2)->(correct alphabet?)
rangschikking::String->String->String->Bool
rangschikking _ [] _ = True
rangschikking _ _ [] = False
rangschikking (a:as) (v:vs) (w:ws)
	| v == w	= rangschikking (a:as) vs ws
	| a == w	= False
	| a == v	= True
	| otherwise	= rangschikking as (v:vs) (w:ws)

--Andries 17 jan 2012