Function which combine new columns from a table to another table - list

I need a little help with two tables issues:
How to achieve simple horizontal union of 2 tables?
Like this:
table2table :: Table -> Table -> Table
table1 = [["Zoe", "2", "1"],
["Mark", "2", "5"]]
table2 = [["Zbir", "4", "7"],
["Nels", "1", "3"]]
table2table = [["Zoe", "2", "1"], ["Zbir", "4", "7"],
["Mark", "2", "5"], ["Nels", "1", "3"]]

For a general way to perform such combination, you can make use of concat . transpose:
> concat . transpose $ [table1, table2]
[["Zoe","2","1"],["Zbir","4","7"],["Mark","2","5"],["Nels","1","3"]]
And it works for more than two lists, if you need it:
> concat . transpose $ [table1, table2, table1]
[["Zoe","2","1"],["Zbir","4","7"],["Zoe","2","1"],
["Mark","2","5"],["Nels","1","3"],["Mark","2","5"]] -- manually formatted
transpose groups them "by columns", concat flattens the lists back.
Another way to mix the lists is by doing it in the diagonal manner:
> diagonal [table1, table2]
[["Zoe","2","1"],["Zbir","4","7"],["Mark","2","5"],["Nels","1","3"]]
For two lists the results are the same as concat . transpose, but with more lists they are different.
> diagonal [table1, table2, table1]
[["Zoe","2","1"],["Zbir","4","7"],["Mark","2","5"],
["Zoe","2","1"],["Nels","1","3"],["Mark","2","5"]]

Seems you want to mix two lists together - a simple solution could be
mix :: [a] -> [a] -> [a]
mix xs [] = xs
mix [] ys = ys
mix (x:xs) (y:ys) = x:y:mix xs ys
table2table :: Table -> Table -> Table
table2table = mix
note that this does not really take the "table"-like representation into account but you really just have a list-of lists and Haskell does not really care how you write down the parts of this list into lines in the editor.

Related

f# iterate and use List<List<string>>

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

List of tuples into a single list with the second elements

I am trying to convert a list of tuples(A*B) into a list of (B). How would I approach this? As I ultimately am trying to get the second value from a map so therefore I first turned it into a list but I am struggling removing the first elements from the list as I do not need them.
I got something like this:
map |> Map.toList
now I figured I had to use List.filter but I do not see how to set up a bool expression to evict the 1st values from list so maybe its better to create a entirely new list with the seconds values.
Any help would be appreciated!
Easy:
["a", 1; "b", 2]
|> List.map snd
|> printfn "%A"
Another way:
["a", 1; "b", 2]
|> List.map (fun (a, b) -> b)
|> printfn "%A"
By the way the module Map refers to a different type than List. A Map is an immutable Dictionary: https://msdn.microsoft.com/visualfsharpdocs/conceptual/collections.map%5b%27key%2c%27value%5d-class-%5bfsharp%5d

How to transform array with duplicates into array with sum of duplicates?

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

How to display the list but without a certain item.

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

Filter a list of my own type - Tuples?

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