I have simple list that contains inside list
let ftss = [
["a","aData"],["b","bData"]
]
I want to iterate and access the elements "a" and "aData" etc.
I tried
List.iter (fun item ->
for i in 0..1 do
printfn "%s" item[i])
how do i access the elements inside the internal list?
Thanks
So, 1st thing is a comma isnt a delimter in a list, but in a tuple ',' so
let ftss = [
["a","aData"],["b","bData"]
]
is actually of type
val ftss: ((string * string) list * (string * string) list) list =
i.e. its a list of 1 entry of a tuple of a list of 1 entry each of a tuple.
which I THINK isnt what you intended?
I THINK you want (a ';' or new line delimits each entry)
let ftss3 = [
["a";"aData"]
["b";"bData"]
]
which is
val ftss3: string list list = [["a"; "aData"]; ["b"; "bData"]]
i.e. a list of a list of strings.
(I'd try to use FSI to enter these things in, and see what the types are)
so to iterate this list of lists you would go
List.iter (fun xs ->
List.iter (fun x ->
printfn "%s" x)
xs)
ftss3
As pointed out in the existing answer, you probably want to represent your data as a list of lists, for which you need to use the ; delimiter (to make a list) rather than , to construct a singleton containing a tuple.
I would just add that if you want to perform an imperative action with each of the items, such as printing, then it is perfectly reasonable to use an ordinary for loop:
let ftss = [
["a"; "aData"]; ["b"; "bData"]
]
for nested in ftss do
for item in nested do
printfn "%s" item
So I've been struggling with this for a few hours now. I have this array [[[4,2]],[[1,2],[1,1]]] and I'd like to transform this array into [[[4,2]],[[1,3]]].
So a function with type f :: [[[Integer]]] -> [[[Integer]]]
Problem
I have a 2d array with inner arrays of length 2: [[x,y] .. ]
An inner array is a duplicate if its head element is repeated: [[1,2],[1,1]]
If there are duplicates I want to take the sum of all the tails and create a new array with the head as the duplicate value and the sum of duplicates as the tail value: [[1,2],[1,1]] becomes [[[1,3]]
What I have
dup [x,_] [y,_] = x == y
sample = [[[3,5],[2,3],[1,1]],
[[3,5],[2,3],[4,2],[1,2]],
[[3,5],[2,3],[4,2],[1,2]],
[[4,2],[1,2],[1,1]]]
ifDuplicateGroup = map (groupBy dup) sample
getSumOfDups n = map sum [concat $ map tail y | y <- n, (length y) > 1]
sumOfSample = map getSumOfDups sample
Returns:
sumOfSample = [[],[],[],[3]]
Desired Result:
sumOfSample =
[[[3,5],[2,3],[1,1]],
[[3,5],[2,3],[4,2],[1,2]],
[[3,5],[2,3],[4,2],[1,2]],
[[4,2],[1,3]]]`
this is the best I could work through. Please help! I cant figure out how to get the desired result.
(Preliminary note: if your innermost lists always have two elements, you should consider using pairs instead, as in [[(4,2)],[(1,2),(1,1)]]. That would make it unnecessary to deal with impossible cases or to worry about getting lists with wrong lengths that your function can't handle. That said, in what follows I will use the types you originally proposed.)
Though you didn't use it in sumOfSample, you were on the right track with ifDuplicateGroup:
-- I have specialised the functions to Integer; they could be more general.
-- Also note that dup is partial; it only works with lists of two elements.
-- That is the sort of issue you might avoid by using pairs.
dup :: [Integer] -> [Integer] -> Bool
dup [x,_] [y,_] = x == y
-- Making it a function by not supplying 'sample'.
ifDuplicateGroup :: [[[Integer]]] -> [[[[Integer]]]]
ifDuplicateGroup = map (groupBy dup)
ifDuplicateGroup will give you a quadryply nested list -- a list of grouped two-element lists. The next step is changing that back into a triply nested list by squashing the groups and thus removing the duplicates. That can be done through a fold, applied through two layers of mapping (so that the lists being folded are the groups of innermost lists):
-- Combining function for the fold. Note that, just like dup, it is partial.
dedup :: [Integer] -> [Integer] -> [Integer]
dedup [x, acc] [_, y] = [x, acc + y]
-- foldl1' doesn't work with empty lists. That is not a problem here, given
-- that group does not produce empty (inner) lists.
sumOfSample :: [[[[Integer]]]] -> [[[Integer]]]
sumOfSample = map (map (foldl1' dedup)) . ifDuplicateGroup
-- Or, equivalently:
-- sumOfSample = map (map (foldl1' dedup) . groupBy dup)
One caveat is that groupBy only groups adjacent elements, and so you have e.g.:
GHCi> sumOfSample [[[4,2],[4,4]],[[1,2],[2,1],[1,1]]]
[[[4,6]],[[1,2],[2,1],[1,1]]]
If that is not acceptable, working around that is possible, though it may be quite annoying and/or require a somewhat different approach. (Unless you don't care about the order in the "middle layer" inner lists, in case you can simply use ifDuplicateGroup = map (groupBy dup . sort) sample, as Renezee points out in the comments.)
Deep list make code hard to understand. Does using type alias help?
This is my ad hoc solution.
import Data.List
type Pair = [Int]
type PairList = [Pair]
sample :: [PairList]
sample = [[[3,5],[2,3],[1,1]],
[[3,5],[2,3],[4,2],[1,2]],
[[3,5],[2,3],[4,2],[1,2]],
[[4,2],[1,2],[1,1]]]
dupList :: PairList -> PairList
dupList xs = ss
where gs = groupBy dup xs
ss = map sumGroup gs
sumGroup :: PairList -> Pair
sumGroup xs = [h,t]
where h = head $ head xs
t = sum $ concatMap tail xs
dup :: Pair -> Pair -> Bool
dup xs ys = head xs == head ys
main :: IO ()
main = do
putStrLn "input"
mapM_ print sample
putStrLn "output"
let output = map dupList sample
mapM_ print output
yeild
>runhaskell listlist.hs
input
[[3,5],[2,3],[1,1]]
[[3,5],[2,3],[4,2],[1,2]]
[[3,5],[2,3],[4,2],[1,2]]
[[4,2],[1,2],[1,1]]
output
[[3,5],[2,3],[1,1]]
[[3,5],[2,3],[4,2],[1,2]]
[[3,5],[2,3],[4,2],[1,2]]
[[4,2],[1,3]]
If Pair only have 2 members, eg. [a,b], you should use tuple (a,b) and use fst,snd instead of head,tail
I have the following list, that contains a list of strings..
I have already searched the orginal list for the lists that contain the string "tom" and got the following list
[["leo", "tom"], ["meg", "tom"], ["George", "john", "adam", "tom"] ]
I now wish to display this list without "tom", i would do this through list comprehension but i don't know how to do that for a list that contains lists? Can someone help me into the right direction?
Writing this as a list comprehension would get complicated, I think. Easier to just chain simple functions.
-- Intended as l `without` x
without :: Eq a => [a] -> a -> [a]
without l x = filter (/= x) l
containing :: Eq a => [[a]] -> a -> [[a]]
containing l x = filter (x `elem`) l
listsWithTom = lists `containing` "tom"
listsMinusTom = map (`without` "tom") listsWithTom
notom xss = [[ x | x <- xs, x /= "tom"] | xs <- xss]
Or
notom = map (filter (/= "tom"))
Or in your particular case
notom = map init
How can I filter a list of this type by the third item in the tuple:
type Car = (String, [String], Int [String])
I saw the snd and fst methods but here i dont think this will work and im not sure how to map without using the '_' wildcard.
There aren't any pre-defined functions like fst or snd for tuples with more than two elements. As you said, you can use pattern matching and the wild card _ to do the job.
cars = [ ("Foo", ["x", "y"], 2009, ["ab", "cd"]
, ("Bar", ["z"], 1997, [])
]
newCars = filter condition cars
where condition (_, _, n, _) = n > 2005
However, this is usually a sign that you should change from using tuples to a record type.
data Car = Car { model :: String
, foo :: [String]
, year :: Int
, bar :: [String]
}
cars = [ Car "Foo" ["x", "y"] 2009 ["ab", "cd"]
, Car "Bar" ["z"] 1997 []
]
Now, you can use model, foo, year and bar like you would use fst and snd on tuples.
newCars = filter ((> 2005) . year) cars
Or you could just use Data.Tuple.Utils?
MissingH is full of other good stuff too; almost all of my projects use it somewhere or other.
Here is my solution for a similar problem:
--construct a list of stock records with the number in stock less than the reorder level.
getstock (name, stock, reorder) = stock
getreorder (name, stock, reorder) = reorder
check l = filter (\x ->(getstock x < getreorder x)) l
main = print(check [("RAM",9,10),("ROM",12,10),("PROM",20,21)]); --[("RAM",9,10),("PROM",20,21)]
The key was to understand that the filter function takes a predicate, not a boolean value.
So, simply saying
filter(getstock < getreorder)
would not work,
while
`filter (getstock < 10)
would