I have two strings
a :: [String]
a = ["A1","A2","B3","C3"]
and
b :: [String]
b = ["A1","B2","B3","D5"]
And I want to calculate the difference between two strings based on the first character and second character and combination of two characters.
If the combination of two elements are the same, it would be calculate as 1
The function I declared is
calcP :: [String] -> [String] -> (Int,[String])
calcP (x:xs) (y:ys) = (a,b)
where
a = 0 in
???
b = ????
I know that I should have a increment variable to count the correct element, and where I should put it in? For now I totally have no idea about how to do that, can anyone give me some hint??
The desired result would be
(2,["B2","D5"])
How should I do that?
I assume that the lists have the same size.
The differences between the two lists
Let's focus on the main part of the problem:
Prelude> a=["A1","A2","B3","C3"]
Prelude> b=["A1","B2","B3","D5"]
First, notice that the zip method zips two lists. If you use it on a and b, you get:
Prelude> zip a b
[("A1","A1"),("A2","B2"),("B3","B3"),("C3","D5")]
Ok. It's now time to compare the terms one to one. There are many ways to do it.
Filter
Prelude> filter(\(x,y)->x/=y)(zip a b)
[("A2","B2"),("C3","D5")]
The lambda function returns True if the elements of the pair are different (/= operator). Thus, the filter keeps only the pairs that don't match.
It's ok, but you have to do a little more job to keep only the second element of each pair.
Prelude> map(snd)(filter(\(x,y)->x/=y)(zip a b))
["B2","D5"]
map(snd) applies snd, which keeps only the second element of a pair, to every discordant pair.
Fold
A fold is more generic, and may be used to implement a filter. Let's see how:
Prelude> foldl(\l(x,y)->if x==y then l else l++[y])[](zip a b)
["B2","D5"]
The lambda function takes every pair (x,y) and compares the two elements. If they have the same value, the accumulator list remains the identical, but if the values are different, the accumulator list is augmented by the second element.
List comprehension
This is more compact, and should seem obvious to every Python programmer:
Prelude> [y|(x,y)<-zip a b, x/=y] -- in Python [y for (x,y) in zip(a,b) if x!= y]
["B2","D5"]
The number of elements
You want a pair with the number of elements and the elements themselves.
Fold
With a fold, it's easy but cumbersome: you will use a slightly more complicated accumulator, that stores simultaneously the differences (l) and the number of those differences (n).
Prelude> foldl(\(n,l)(x,y)->if x==y then (n,l) else (n+1,l++[y]))(0,[])$zip a b
(2,["B2","D5"])
Lambda
But you can use the fact that your output is redundant: you want a list preceeded by the length of that list. Why not apply a lambda that does the job?
Prelude> (\x->(length x,x))[1,2,3]
(3,[1,2,3])
With a list comprehension, it gives:
Prelude> (\x->(length x,x))[y|(x,y)<-zip a b, x/=y]
(2,["B2","D5"])
Bind operator
Finally, and for the fun, you don't need to build the lambda this way. You could do:
Prelude> ((,)=<<length)[y|(x,y)<-zip a b,x/=y]
(2,["B2","D5"])
What happens here? (,) is a operator that makes a pair from two elements:
Prelude> (,) 1 2
(1,2)
and ((,)=<<length) : 1. takes a list (technically a Foldable) and passes it to the length function; 2. the list and the length are then passed by =<< (the "bind" operator) to the (,) operator, hence the expected result.
Partial conclusion
"There is more than than one way to do it" (but it's not Perl!)
Haskell offers a lot of builtins functions and operators to handle this kind of basic manipulation.
What about doing it recursively? If two elements are the same, the first element of the resulting tuple is incremented; otherwise, the second element of the resulting tuple is appended by the mismatched element:
calcP :: [String] -> [String] -> (Int,[String])
calcP (x:xs) (y:ys)
| x == y = increment (calcP xs ys)
| otherwise = append y (calcP xs ys)
where
increment (count, results) = (count + 1, results)
append y (count, results) = (count, y:results)
calcP [] x = (0, x)
calcP x [] = (0, [])
a = ["A1","A2","B3","C3"]
b = ["A1","B2","B3","D5"]
main = print $ calcP a b
The printed result is (2,["B2","D5"])
Note, that
calcP [] x = (0, x)
calcP x [] = (0, [])
are needed to provide exhaustiveness for the pattern matching. In other words, you need to provide the case when one of the passed elements is an empty list. This also provides the following logic:
If the first list is greater than the second one on n elements, these n last elements are ignored.
If the second list is greater than the first one on n elements, these n last elements are appended to the second element of the resulting tuple.
I'd like to propose a very different method than the other folks: namely, compute a "summary statistic" for each pairing of elements between the two lists, and then combine the summaries into your desired result.
First some imports.
import Data.Monoid
import Data.Foldable
For us, the summary statistic is how many matches there are, together with the list of mismatches from the second argument:
type Statistic = (Sum Int, [String])
I've used Sum Int instead of Int to specify how statistics should be combined. (Other options here include Product Int, which would multiply together the values instead of adding them.) We can compute the summary of a single pairing quite simply:
summary :: String -> String -> Statistic
summary a b | a == b = (1, [ ])
| otherwise = (0, [b])
Combining the summaries for all the elements is just a fold:
calcP :: [String] -> [String] -> Statistic
calcP as bs = fold (zipWith summary as bs)
In ghci:
> calcP ["A1", "A2", "B3", "C3"] ["A1", "B2", "B3", "D5"]
(Sum {getSum = 2},["B2","D5"])
This general pattern (of processing elements one at a time into a Monoidal type) is frequently useful, and spotting where it's applicable can greatly simplify your code.
I have the following function that searches through [Char] and returns [Char] based on their index number:
myList = "abcdefghijk"
searchText = foldl (\acc el -> if elemIndex el myList > Just 11 then el : acc else acc) [] myList
Clearly this is somewhat inefficent as elemIndex returns the index number of each element then applies the condition.
Is there a more efficient way of performing this operation?
The usual approach is to pair each character with its index before doing the real processing
process $ zip [0..] myList
Now process can perform the actual computation, which can use the indexes as well as the characters.
In some contexts, this approach is known as the Schwartzian transform.
Your function returns a string that skips the first twelve characters and reverses the output, dropping any characters that are also in those first twelve.
For a more efficient version of this, you could use Data.Set to store those first twelve characters for fast lookup, the filter them out and reverse the remainder of the string:
import qualified Data.Set as Set
searchText =
let hash = (Set.fromList . take 12) myList
in (reverse . filter (flip Set.notMember hash) . drop 12) myList
I have a list of tuples, which I am trying to use its elements to reach a nested list's elements.
list = [["c","a","b"],["k","l","m"]]
indexTuple = [(0,1),(1,1),(1,2)]
this way I need to check whether there is an "a" in one of the elements of the list corresponding to my indexTuple's elements. My attempt so far;
seekinga :: [[[Char]]] -> Int -> Int -> Int -> [(Int,Int)]
seekinga list x y width
| list !!(map fst indexTuple) !!(map snd indexTuple) == "a" = [(fst indexTuple,snd indexTuple)]
| otherwise = [()]
where indexTuple = [(x,y) | x <- [x-width..x+width], y <- [y-width..y+width]]
this obviously does not work, because the !! operator wants integers to work on, but map returns lists. Any suggestions are very much appreciated.
You really have two separate concerns: given two numbers, how do you index into a nest list and how do you get two numbers out of a tuple.
The first problem is easy to solve just by looking at types. You know how to index into one list: (!!) :: [a] -> Int -> a. Here, a can be anything, including a nested list. So, given [[[Char]]], we can use !! to get a [[Char]]. And, since this is a list itself, we can use !! again to get a [Char]. ([Char] is just String, in case you don't realize.)
So all we need to do here is use !! then use it again on the result of the first one.
Now, how do we actually get the two numbers out? This is where we use pattern matching. We can just match against a tuple with a let statement:
let (i, j) = tuple in ...
Now just put the two together and you're set.
So you can view an element with:
> list !! 1 !! 2
"m"
So lets make this a function:
:set -XNoMonomorphismRestriction
> let index lst i j= lst !! i !! j
And lets filter out those indexs which do not point to "a"
> filter (\(i, j) -> index list i j == "a") indexTuple
[(0,1)]
If instead
list = [["c","a","b"],["k","l","a"]]
then
> filter (\(i, j) -> index list i j == "a") indexTuple
[(0,1),(1,2)]
Using !! may not be your best option however, in fact it probably is not. I tried to break out the two parts of the problem, as I understood it, access the element and filter for indexes.
I would like to know if there is a simple way to turn [5,2,10] into "52a".
Where its not just to this case, I want to associate any number >9 with the corresponding letter.
Thanks in advance.
You want to do something to each element of a list in order to get a new list. In other words, you want to apply a function (that you will have to define yourself) to each element. This is what the map function from the Prelude is for.
To convert between integers and individual characters, you could use the chr and ord functions from the Data.Char module.
So,
map (\i -> if i < 10 then chr (i + ord '0') else chr (i - 10 + ord 'a'))
is a function of type [Int] -> String that does what you want (no error checking included, though).
Slower but more elegant:
f = map ((['0'..'9'] ++ ['a'..'z']) !!)
If your numbers are 0-15 use map intToDigit from Data.Char.
I am trying to do basic list operations with SML.
I want to extract each element of the list and append string to that element and add it back to the list.
Example:
List : [A,B,C,D]
String : A
Final List: [AA,AB,AC,AD]
How can I iterate through each element in the list in SML? I can append strings using ^ and concatenate lists using # but how do I extract each element from the list?
Also can we use something like map or arrays to store these list values and pass it to different functions in SML?
I could just find some vague information about map and no definite information as to how we can use it.
two easy ways to do this:
- fun addstring (x::xs) a = (a^x) :: addstring xs a
= | addstring [] a = []
= ;
val addstring = fn : string list -> string -> string list
- addstring ["A", "B", "C", "D"] "A";
val it = ["AA","AB","AC","AD"] : string list
The above uses pattern matching to destruct the list, performs the operation, then constructs the list again, recursing as it goes.
- fun addstring2 xs a = map (fn x => a^x) xs;
val addstring2 = fn : string list -> string -> string list
- addstring2 ["A", "B", "C", "D"] "A";
val it = ["AA","AB","AC","AD"] : string list
This one is a fair bit simpler (if perhaps a tiny bit harder to read than the explicit cases in addstring.) but it shows how map is used - you specify a function that maps each element from the source to the target domain, give it a list of elements in the source domain, and it returns a list in the target domain.
of course, neither of these do in-place updating of the list, they return the new list.