Retrieve matching values from branch to leaf - list

So im trying to make a tree with companies as the branch and subcompanies of the company as leafs.
Every company/subcompany consists of a name, a gross income and a list with their subcompanies.
I've made a function that returns a tuple with (name,gross income) for all the companies/subcompanies in the company tree.
What I would like to do now, is to find the total income for a certain company/subcompany, which means that the function should add all the subcompanies gross income together with the companies and return the result. It should only have a string as input (the name of the company).
type Department = a' list
and a' = | SubDep of string * float
| Company of string * float * Department;;
let company =
Company("Arla", 1000.0, [SubDep("Karolines Køkken", 500.0);
Company("Lurpak", 200.0, [SubDep("Butter",100.0); SubDep("Milk", 100.0)]);
SubDep("Arla Buko", 100.0);
Company("Riberhus", 200.0, [SubDep("Cheese",200.0)])
]);;
So an example run should be:
companyTotalIncome "Arla" company;;
And the result should be: 2400

To sum everything up you can do something like this (don't really know why you'll need the name of the company in here as for your example you just summed it all up):
let rec depIncome =
function
| SubDep (_, income) -> income
| Company (_,income, sub) -> income + totalIncome sub
and totalIncome =
List.sumBy depIncome
but your data structures are real strange (why list of companies a department?)
I would do maybe like this:
type Department =
{ name : String
income : float
}
type Company =
{ name : String
departmens : Department list
subCompanies : Company list
}
and then
let rec income company =
company.departments |> List.sumBy (fun d -> d.income }
+ company.subCompanies |> List.sumBy income
of course you can move the income to the company too (or add one there too) - I really don't know what you want to do - just my 5cts.

Related

Calculating the value of a field based on the difference between the values of another field in two adjacent positions using haskell

I have a list of custom data objects which track an increasing total value on a daily basis using one field total. Another field in the custom data type is the value new. Using a csv file I have read in the values for date and total and am trying to calculate and set the values for new from these values.
data item = Item{
date :: Day,
total :: Int,
new :: Int
}
Before
date
total
new
01/01/2021
0
0
02/01/2021
2
0
03/01/2021
6
0
04/01/2021
15
0
After
date
total
new
01/01/2021
0
0
02/01/2021
2
2
03/01/2021
6
4
04/01/2021
15
9
My understanding is that in haskell I should be trying to avoid the use of for loops which iterate over a list until the final row is reached, for example using a loop control which terminates upon reaching a value equal to the length of the list.
Instead I have tried to create a function which assigns the value of new which can used with map to update each item in the list. My problem is that such a function requires access to both the item being updated, as well as the previous item's value for total and I'm unsure how to implement this in haskell.
--Set daily values by mapping single update function across list
calcNew:: [Item] -> Int -> [Item]
calcNew items = map updateOneItem items
-- takes an item and a value to fill the new field
updateOneItem :: Item -> Int -> Item
updateOneItem item x = Item date item total item x
Is it possible to populate that value while using map? If not, is a recursive solution required?
We can do this by zipping the input list with itself, shifted by one step.
Assuming you have a list of items already populated with total values, which you want to update to contain the correct new values (building an updated copy of course),
type Day = Int
data Item = Item{ -- data Item, NB
date :: Day,
total :: Int,
new :: Int
} deriving Show
calcNews :: [Item] -> [Item]
calcNews [] = []
calcNews totalsOK#(t:ts) = t : zipWith f ts totalsOK
where
f this prev = this{ new = total this - total prev }
This gives us
> calcNews [Item 1 0 0, Item 2 2 0, Item 3 5 0, Item 4 10 0]
[Item {date = 1, total = 0, new = 0},Item {date = 2, total = 2, new = 2},
Item {date = 3, total = 5,new = 3},Item {date = 4, total = 10, new = 5}]
Of course zipWith f x y == map (\(a,b) -> f a b) $ zip x y, as we saw in your previous question, so zipWith is like a binary map.
Sometimes (though not here) we might need access to the previously calculated value as well, to calculate the next value. To arrange for that we can create the result by zipping the input with the shifted version of the result itself:
calcNews2 :: [Item] -> [Item]
calcNews2 [] = []
calcNews2 (t:totalsOK) = newsOK
where
newsOK = t : zipWith f totalsOK newsOK
f tot nw = tot{ new = total tot - total nw }

Sml tuples length

I was interested in if there is a possible way to get length of tuple in sml?! See example
val tes = ((1,"test"),("test","some"))
Lenght(tes) = 2
I want it for a problem solve there is a problem which says to get students list which contains list for each student information but student information are different in two types some are like
(1,"test","nick")
and some are like
("name","nick")
So it wants to return the first element of each list in student lists see below:
((1,"test","nick"),("test2","nick2"),(2,"test3","nick3"))
Return > (1,"test2",2)
Here more info M Molbdnilo
#molbdnilo
An example of what you're most likely expected to do; define some useful sum types.
First, let's invent two ways to identify a person:
datatype Person = JustName of string
| NameAndNumber of string * int
datatype Identifier = Name of string
| Number of int
then you can get an Identifier for a Person:
fun identifier (JustName n) = Name n
| identifier (NameAndNumber (_, i)) = Number i
Let's test with some people:
- val people = [JustName "A", NameAndNumber ("B", 23), JustName "C", NameAndNumber ("D", 22)];
val people =
[JustName "A",NameAndNumber ("B",23),JustName "C",NameAndNumber ("D",22)]
: Person list
- map identifier people;
val it = [Name "A",Number 23,Name "C",Number 22] : Identifier list

Converting a list to a map in Scala

I want to create a simple program that calculates someone's age after x years. so first you assign someone's current age to a variable, and then I want to use map to display the future ages.
What I have so far is:
val age = 18
val myList = (1 to 2000).toList
Basically, I want the numbers from the list and make it a map key. And for the value, it's a sum of variable and key. so the map would look like this:
1 -> 19, 2 -> 20, 3 -> 21......
How can I accomplish this?
Consider mapping to tuples
val age = 18
val ageBy: Map[Int, Int] = (1 to 2000).map(i => i -> (age + i)).toMap
ageBy(24) // res1: Int = 42

Haskell, how to implement SQL like operations?

I’m trying to do some SQL-like operations with Haskell, but I have no idea about what data structures to use. I have 3 different tables: customer, sales, and order. The schemas are below:
Customer
custid — integer (primary key)
name — string
Example:
1|Samson Bowman
2|Zelda Graves
3|Noah Hensley
4|Noelle Haynes
5|Paloma Deleon
Sales
orderid — integer (primary key)
custid — integer
date — string
Example:
1|3|20/3/2014
2|4|25/4/2014
3|5|17/7/2014
4|9|5/1/2014
5|5|9/6/2014
Order
orderid — integer
item — string
Example:
2|gum
4|sandals
3|pen
1|gum
2|pen
3|chips
1|pop
5|chips
What i want to do is to “merge” these three tables into a new table, and the schema of new table is:
Customername Order# Date Items
Samson Bowman 17 20/3/2014 shoes, socks, milk
Samson Bowman 34 19/5/2014 gum, sandals, butter, pens, pencils
Paloma Deleon 41 6/1/2014 computer
…
So yeah, it is very SQL like. I know the SQL is very simple, but how can I implement this without SQL but instead using built-in data structure?
TEXT PRINT ERROR
When i run the function , it shows the following error:
Couldn't match type `[Char]' with `Char'
Expected type: Customer -> String
Actual type: Customer -> [String]
In the first argument of `map', namely `formatCustomer'
In the second argument of `($)', namely `map formatCustomer result'
And i am thinking that the return type of condense is [Customer], but formatCustomer uses only Customer. is this the reason?
All of your associations are one-to-many, and they don’t refer to eachother; it is strictly hierarchical. Customers have sales, sales have orders. Given that, you probably wouldn’t store each bit of information separately, but hierarchically as it truly is. I might put it into data types like this:
data Customer = Customer { customerName :: String
, sales :: [Sale]
} deriving (Eq, Read, Show)
data Sale = Sale { saleDate :: Day
, soldItems :: [String]
} deriving (Eq, Read, Show)
This will probably be very easy to manipulate from within Haskell, and, as a bonus, it’s very easy to turn into the table you wanted to end up with, simply because it’s so close to that in the first place.
But maybe I’ve misinterpreted your question and you’re not just asking for the best data structure to hold it, but how to convert from your flat data structure into this sort of structure. Fortunately, that’s easy enough. Since everything is keyed, I’d construct a Map and start unionWithing things in, or even better, do both at once with fromListWith. To put that more concretely, say you have these data structures:
data DBCustomer = DBCustomer { dbCustomerName :: String
, dbCustomerID :: Int
} deriving (Eq, Read, Show)
data DBSale = DBSale { saleOrderID :: Int
, saleCustomerID :: Int
, dbSaleDate :: Day
} deriving (Eq, Read, Show)
data DBOrder = DBOrder { dbOrderID :: Int
, dbOrderItem :: String
} deriving (Eq, Read, Show)
If I wanted a function with the type [DBSale] -> [DBOrder] -> [Sale], I could write it easily enough:
condense :: [DBSale] -> [DBOrder] -> [Sale]
condense dbSales dbOrders = flip map dbSales $ \dbSale ->
Sale (dbSaleDate dbSale)
$ fromMaybe [] (Map.lookup (saleOrderID dbSale) ordersByID) where
ordersByID = Map.fromListWith (++) . flip map dbOrders
$ \dbOrder -> (dbOrderID dbOrder, [dbOrderItem dbOrder])
Here I’m discarding the customer ID since there’s no slot in Sale for that, but you could certainly throw in another Map and get whole Customer objects out:
condense :: [DBCustomer] -> [DBSale] -> [DBOrder] -> [Customer]
condense dbCustomers dbSales dbOrders = flip map dbCustomers $ \dbCustomer ->
Customer (dbCustomerName dbCustomer)
$ lookupDef [] (dbCustomerID dbCustomer) salesByCustomerID where
lookupDef :: (Ord k) => a -> k -> Map.Map k a -> a
lookupDef def = (fromMaybe def .) . Map.lookup
salesByCustomerID = Map.fromListWith (++) . flip map dbSales
$ \dbSale -> (saleCustomerID dbSale,
[ Sale (dbSaleDate dbSale)
$ lookupDef [] (saleOrderID dbSale)
ordersByID])
ordersByID = Map.fromListWith (++) . flip map dbOrders
$ \dbOrder -> (dbOrderID dbOrder, [dbOrderItem dbOrder])
Printing
This should be reasonably easy. We’ll use Text.Printf since it makes putting things in columns easier. On the whole, each row in the result is a Sale. First, we can try formatting a single row:
formatSale :: Customer -> Sale -> String
formatSale customer sale = printf "%-16s%-8d%-10s%s"
(customerName customer)
(orderID sale)
(show $ saleDate sale)
(intercalate "," $ soldItems sale)
(Actually, we discarded the order ID; if you want to preserve that in your output, you’ll have to add that into the Sale data structure.) Then to get a list of lines for each customer is easy:
formatCustomer :: Customer -> [String]
formatCustomer customer = map (formatSale customer) $ sales customer
And then to do it for all customers and print it out, if customers was the output of condense:
putStr . unlines $ concatMap formatCustomer customers
I have some similar problems and the best I found to do SQL Join operations is to use the align function from the these package, combined with Map (where the key is on what you want to join).
The result of align will give you a map or list of These a b which is either an a, a b or both. That's pretty neat.

Filter a list of lists

I would like to know how to filter a whole list out of list of lists
Example: [ ["Bob", "Baker", "male", "70000"],
["Alice", "Allen", "female", "82000"] ]
And now I would like to filter the list which contains female. So output would be:
["Alice", "Allen", "female", "82000"]
Thanks
Ankur's answer will certainly solve your problem, but I would like to make a suggestion that could make your life easier. It seems that you're storing all your data as strings in lists, but really what you'd like is a data type that could hold all this data in a more organized fashion, which can be done using Haskell data types, something like:
data Person = Person {
firstName :: String,
lastName :: String,
gender :: String,
salary :: String
} deriving (Eq, Show)
Then you could easily sort your data with filter (("female" ==) . gender) a. While this is a bit more code up front, later on if you were to add a "title" field for "Mr", "Mrs", etc, then it wouldn't matter if you added it at as the first field or the last field, this code would still work. Also, if for whatever reason you had an invalid value like ["Bob", "Baker", "male", "70000", "female"], Ankur's solution would give you an incorrect result, but with a custom data type, this would not even compile.
You could further improve your data structure with a few tweaks. I would suggest making a data type for gender, and then use Int or Double for the salary field, so you would have
data Gender = Male | Female deriving (Eq, Show, Read)
data Person = Person {
firstName :: String,
lastName :: String,
gender :: Gender,
salary :: Int
} deriving (Eq, Show)
filtGender :: Gender -> [Person] -> [Person]
filtGender gend people = filter ((gend ==) . gender) people
main :: IO ()
main = do
let people = [Person "Bob" "Baker" Male 70000,
Person "Alice" "Allen" Female 82000]
putStr "The females are: "
print $ filtGender Female people
putStr "The males are: "
print $ filtGender Male people
Prelude> let a = [ ["Bob", "Baker", "male", "70000"], ["Alice", "Allen", "female", "82000"] ]
Prelude> filter (elem "female") a
[["Alice","Allen","female","82000"]]