Getting elements from a list by an index list - list

I have two lists in Haskell.
Original list containing string values:
["Hello", "HELLO", "", "WORLD", "xxx", "world"]
Index list containing integer values where the strings are all upper case in the original list:
[1,3]
I incremented all the values in the index list with a function I created and make index2 list, overall it looks like this:
My code:
import Data.List
import Data.Char
import Data.Maybe
main = do
contents <- readFile "h.txt"
let original = lines (contents)
let allUpper = lines (map toUpper contents)
let onlyUpper = filter(/="") (intersect original allUpper)
let upperIndex = findIndices ('elem' onlyUpper) original
let index2 = (map increment upperIndex)
print index2
increment :: Int -> Int
increment x = x+1
I have managed to came this far with the help of yours. However, since I am a beginner I do not seem to understand how iteration over lists works.
The thing I want to accomplish is to check whether the corresponding index values (in index2) are empty or not in the original list, if they are empty, I want to remove them in index2.

Filtering empty elements
The thing I want to accomplish is to check whether the corresponding
index values (in index2) are empty or not in the original list, if
they are empty, I want to remove them in index2.
The code already filters out empty elements! Look at the following line:
let onlyUpper = filter(/="") (intersect original allUpper)
This line does two things:
it keeps only elements which are constituted only with uppercase letters(intersect original allUpper),
it filters out empty elements (filter(/="")).
If by empty elements you mean strings which contains only space characters or nothing, you can use instead:
filter (all isSpace)
Iterating over lists
I do not seem to understand how iteration over lists works.
In Haskell, lists are single chained lists: each element contains a value and a reference to the next value.
Therefore lists are not indexed: the !! operator have to go through each element to access a specific element making lists completely inefficient when dealing with direct access.
When you’re submitting a list to a function, you simply give it the first element.
With these considerations, when you work on lists, you have to avoid accessing elements via their index.
The idea is to create functions which do their job on simple values and mapping them to list of elements. Take a look at the toUpper function:
toUpper :: Char -> Char
It takes a Char and returns its uppercased version (also a Char).
Haskell does not have a toUpper function which works on String, you have to use something like map or <$> to apply toUpper to a list of char (a String):
map toUpper "ab" -- "AB"
toUpper <$> "ab" -- "AB"
The idea is to have functions which does only one specific thing. Upercasing and iterating over a list are two different things. Does the toUpper function need to know the index of the element it will uppercase? No!
Iterating over a list with index
You may ask: but what if my function REALLY need to consider the index of the elements? (ie: for filtering out even or odd elements).
You have two way of considering it:
a List is not the type you need to work with. Maybe Data.Map, Data.IntMap or Data.Vector are better suited for the task (see these modules for more information),
you need to use an intermediate type which will hold the index.
For example:
let string = "abcde"
let indexedString = zip [1..] string
print indexedString -- [(1, 'a'), (2, 'b), (3, 'c), (4, 'd), (5, 'e)]
Note that this also solves your need of an increment function since the index is started at whatever value you want.
To go back to the original string, you write:
map snd indexedString -- "abcde"
You need to use the fst and snd functions to work with the intermediate type, or to use pattern matching:
filter (\x -> snd x == 'b') indexedString -- [(2, 'b')]
map (\(i,s) -> (i, toUpper s)) indexedString -- [(1,'A'),(2,'B'),(3,'C'),(4,'D'),(5,'E')]
Taking the index into account:
let string = "abcde"
indexedString = zip [1..] string
upperEven (i, c) | even i = (i, toUpper c)
| otherwise = (i, c)
print $ map upperEven indexedString -- [(1,'a'),(2,'B'),(3,'c'),(4,'D'),(5,'e')]
print $ map snd $ map upperEven indexedString -- "aBcDe"
Notes
The increment function already exists in Haskell, it’s called succ (it is also a more generic function which works on every types supporting the Enum class like Int, Char…)

Why not use words :: String -> [String] on the contents you get from a file? Using lines :: String -> [String] would be an alternative if you had one word per line.
Then if i get your problem right, you could write the following to solve your problem:
import Data.List (findIndices)
import Data.Char (isUpper)
allUpperOneBasedIndices :: String -> [Int]
allUpperOneBasedIndices = map succ . findIndices (all isUpper) . words

Related

Calculating the difference between two strings

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.

Efficient list operations?

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

How to use a tuple's elements as indexes to reach a list's elements-haskell

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.

Haskell int list to String

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.

How do I iterate a list?

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.