Reputation: 373
I have a function 'getMin' which should return the minimum value. This function uses another function 'urvalFun' in order to determine this minimim value. Here is a demonstration of 'urvalFun'
get1:: (String,String,Double ) -> String
get1 (x,_,_ ) = x
get2 :: (String,String,Double)-> String
get2 (_,x,_) = x
get3:: (String,String,Double)->Double
get3 (_,_,x) = x
distDiff:: String-> String->[(String,String,Double)] ->Double
distDiff a b diMat = sum [z |(x,y,z)<- diMat, (x == a && y /= b)
|| (y == a && x /= b) ]
urvalFun:: Int -> (String,String,Double)->[(String,String,Double) ]->Double
urvalFun size triple diMat = ((fromIntegral size)-2)*(get3 triple)
- ( (distDiff (get1 triple) (get2 triple) diMat ) + (distDiff (get2 triple)
(get1 triple) diMat ))
Its not necessary to understand this chunck of code, the only thing that is important is that if i evaluate:
urvalFun 3 ("a","b",0.304) [("a","b",0.304),("a","d",0.52),("a","e",0.824)]
this will evaluate to -1.03999
urvalFun 3 ("a","d",0.52) [("a","b",0.304),("a","d",0.52),("a","e",0.824)]
this will evaluate to - 0.60799
urvalFun 3 ("a","e",0.824) [("a","b",0.304),("a","d",0.52),("a","e",0.824)]
this will evaluate to 1.1e^-16
now we know that calling urvalFun with ("a","b",0.304) and [("a","b",0.304),("a","d",0.52),("a","e",0.824)] will get the value which is the smallest. I want to create a function 'getMin' which will return this minimum value (with the same vector as in the above examples as a parameter) ,as shown above. The problem is that it won't work I have no clue why
getMin:: [(String,String,Double)]->Double
getMin diMat = inner 0 diMat 2000
where
inner 3 diMat min = min
inner n diMat min
|current > min = inner (n + 1) (diMatMinus ++ [(head diMat) ]) min
|otherwise = inner (n+1) (diMatMinus ++ [(head diMat) ]) current
current = urvalFun (length diMat) (head diMat) diMat
diMatMinus = tail diMat
try to evaluate for example
getMin [("a","e",0.824),("a","d",0.52),("a","b",0.304)]
which will evaluate to -1.1e^-16
which is not want i intended because I want this to return -1.03999
Could someone help me out here?
(this code is a little bit ad hoc but it is under construction, I am just doing some tests right now)
notice that i have rearranged the vector so that the triple ("a","b",0.304) is the last element in the vector.
Upvotes: 0
Views: 1077
Reputation: 52039
Note that for a list of size 3 your getMin
function may be written:
getMin' [x,y,z]
= minimum [ urvalFun 3 x [x,y,z]
, urvalFun 3 y [y,z,x]
, urvalFun 3 z [z,x,y]
]
You can create the sequence of arguments to the urvalFun
function with zip and and a helper function:
rotate (x:xs) = xs ++ [x]
zip "xyzw" (iterate rotate "xyzw")
= [ ('x', "xyzw"),
('y', "yzwx"),
('z', "zwxy"),
('w', "wxyz") ]
Thus:
import Data.List
getMin tuples = minimum (zipWith go tuples (iterate rotate tuples))
where n = length tuples
go (x,xs) = urvalFun n x xs
Upvotes: 1
Reputation: 116139
You want to find the value in a given list which minimizes your function.
I'll work with a simpler example than yours: finding the string with minimum length. You'll be able to adapt this to your case by replacing the length
function.
> import Data.Foldable
> let list = ["hello", "world!", "here", "is", "fine"]
> minimumBy (comparing length) list
"is"
The above works, but it will call length
every time it performs a comparison, i.e. roughly twice the length of the list. It is also possible to avoid this, and use length
only once per element, by precomputing it:
> snd $ minimumBy (comparing fst) [ (length x, x) | x <- list ]
We first pair each string with its length, take the minimum length-string pair according to the length only, and finally take only the string in such pair.
By the way, I'd recommend you avoid functions such as get1
to access tuples: they are not idiomatic in Haskell code, which usually exploits pattern matching for the same effect: for instance
urvalFun:: Int -> (String,String,Double)->[(String,String,Double) ]->Double
urvalFun size (s1,s2,d) diMat =
(fromIntegral size - 2)*d - distDiff s1 s2 diMat + distDiff s2 s1 diMat
looks more readable.
head,tail
are also particularly dangerous since they are partial: they will crash your program if you ever use them on a empty list, without providing much explanation.
In general, when working with lists, using indexes, or counter variables to count up to the length of the list, is typically not needed and not idiomatic. One can often simply resort to pattern matching and recursion, or even to standard fold/map functions.
Upvotes: 1
Reputation: 811
First you need a way to get the minimum element to pass to urvalFun
. This can be done with minimumBy
.
Observe the following
λ> let ls = [("a","d",0.52),("a","e",0.824),("a","b",0.304)]
λ> let min = minimumBy (\(_,_,c) (_,_,c') -> compare c c') ls
λ> urvalFun 3 min ls
-1.0399999999999998
Or maybe this is what you intended:
λ> minimum [ urvalFun 3 x ls | x <- ls]
-1.0399999999999998
If you also want to alter n from 0 to 3 or something, then this can be further modified. I'd suggest stating in english what you want your function to do.
Upvotes: 3