I have defined both records and created a union from them, but F# still complains that the constructor "Food" is not defined. What is the problem?
type Product = {Name : string; BasePrice: int}
type Size = {Medium: int; Large: int}
type Food = | Product of Product| Size of Size
let food = Food({Name = "Bagel"; BasePrice = 20}; {Medium = 10; Large = 20})
Food is a type, not a constructor - to create a value of type Food you need to use one of the constructors Product or Size. It looks like you're trying to construct a list Food, in which case you can use:
let food = [Product {Name = "Bagel"; BasePrice = 20}; Size {Medium = 10; Large = 20}]
Related
Apologizes if the semantics is erroneous in my question, but the code below should explain what my goal is.
I've created a table like so:
local a1 = {}
a1.hammer = {
price = 10,
quantity = 5,
category = "tools",
}
a1.saw = {
price = 15,
quantity = 4,
category = "tools",
}
a1.screwdriver = {
price = 4,
quantity = 12,
category = "tools",
}
Printing the contents of this table gives:
{hammer = {price = 10,
quantity = 5,
category = "tools"},
saw = {price = 15,
quantity = 4,
category = "tools"},
screwdriver = {price = 4,
quantity = 12,
category = "tools"}}
Question 1: How do I access the price of the screwdriver (ie. field of a table of a table)
Question 2:
How do I:
Save table a1 to a file
Open the file and import the table the next time I run the application
Note: local a2 = a1 returns nil for a2 rather than assigning the reference of a1 to a2. There's an issue here...
#Luke Allison
I may have an answer to your first question:
Question 1: How do I access the price of the screwdriver (ie. field of
a table of a table)
you can try this code:
print( a1["screwdriver"]["price"] )
Result = 4.
As for the second question you should have a look at the link in the comments above.
Hope that helps.
I have a list of clients, which consists of a string * int * string * int * string list. I've made a function where I give a string, an int and a string list. Given some rules, I extract the correct tuple from the list.
An example of three clients:
let client1 = "Jon", 37514986, "Male", 1980, ["Cars"; "Boats"; "Airplanes"]
let client2 = "Jonna", 31852654, "Female", 1990, ["Makeup"; "Sewing"; "Netflix"]
let client3 = "Jenna", 33658912, "Female", 1970, ["Robe Swinging"; "Llamas"; "Music"]
let file1 = [client1; client2; client3]
//Response must be client(s) with different sex, age diff <= 10 and least one common interest
let request (sex:string) (yob:int) (interests:string list) =
Set.fold (fun x (nm,ph,sx,yb,toi) -> if sex<>sx &&
yb-yob < 10
then (nm,ph,sx,yb,toi) else x) ("",0,"",0,[]) (Set.ofList file1)
request "Male" 1976 ["Paper"; "Llamas"; "Space"] //Expected ("Jenna", 33658912, "Female", 1970, ["Robe Swinging"; "Llamas"; "Music"])
So, I guess you can call it kind of a dating bureau. In the above example, I request all clients, which do not share the same sex as me and do not have an age difference larger than 10. I'm not using interests as of now, as I'm still working on that, but it should compare the given interests and the interets of a client and see if there's at least one similarity.
But my current problem is that it stops and returns at the first compatible client, but what if there's more? How do I make it continue and build up a set of clients?
I was trying to do something with Set, hence the Set.ofList, but I'm somehow not feeling I get any of the benefits out of using a Set as it is right now.
I always get confused when using n-tuples (here: quintuple) with n > 3 or non-unique types. Records are much easier to understand:
type Sex = Male | Female
type Client = { name: string; id: int; sex: Sex; YearOfBirth: int; interests: Set<string> }
constructing values is a bit more verbose then:
let client1 = { name = "Jon"; id = 37514986; sex = Male; YearOfBirth = 1980; interests = ["Cars"; "Boats"; "Airplanes"] |> Set.ofList }
let client2 = { name = "Jonna"; id = 31852654; sex = Female; YearOfBirth = 1990; interests = ["Makeup"; "Sewing"; "Netflix"] |> Set.ofList }
let client3 = { name = "Jenna"; id = 33658912; sex = Female; YearOfBirth = 1970; interests = ["Robe Swinging"; "Llamas"; "Music"] |> Set.ofList }
let file1 = [client1; client2; client3]
If you really need to list many values in code, create a helper function (or constructor) mapping tuples to the record.
When filtering the list, you can then match on just the values you need (note that name is not used):
let request sex yob interests =
file1
|> List.filter (fun { sex = s; YearOfBirth = y; interests = i } ->
sex <> s && abs(yob-y)<= 10 && i |> Set.intersect interests |> (not << Set.isEmpty))
request Male 1976 (["Paper"; "Llamas"; "Space"] |> Set.ofList)
val it : Client list =
[{name = "Jenna";
id = 33658912;
sex = Female;
YearOfBirth = 1970;
interests = set ["Llamas"; "Music"; "Robe Swinging"];}]
how would I go about counting the number of times a string occurs in a table?
Basically I have a table that is like, say 200 entires for example (but it is larger)... each entry has a sub entry called name.
so..
itemlist[i].name == somestring.
Now I can search and find a match pretty easy using an if statment while looping though the table...
if string.find(string.lower(itemlist[i].name), string.lower(searchString)) ~= nil then
So say I'm searching for Thomas, it will return when it finds "Thomas F Malone".
The thing is some cases there are more than one result for the search value.. for example.. say there are three different names that all start with Thomas.
At the moment it will just find the 1st occurrence of the Thomas.
So the plan is to count all the occurrences of Thomas and then output all of them... but I can not work out how to get the numeric value of how many times the result is found in the table.
TL;DR - How can I count the number of occurrences that of a string in a table?
When you found the matching values, store them in a temporary table, e.g.
table.insert(temporaryTable, value)
rather than quitting the function using return. You can find below, a sample function which gathers and counts the occurence of a query string in a variable inside of a multidimensional table (or see it in action here).
--data
itemList = {
{name = "Denny Kuhlman", id = "6688"},
{name = "Russell Leisy", id = "3751"},
{name = "Hilario Stermer", id = "1886"},
{name = "Thomas Hemming", id = "9666"},
{name = "Samuel Lafuente", id = "8232"},
{name = "Lazaro Ashby", id = "5274"},
{name = "Ronnie Nicosia", id = "9664"},
{name = "Edison Seyal", id = "1344"},
{name = "Jerald Officer", id = "9497"},
{name = "Lupe Burdge", id = "266"},
{name = "Stephan Iler", id = "5968"},
{name = "Josue Stephens", id = "2128"},
{name = "Salvador Ortmann", id = "3643"},
{name = "Tony Ricker", id = "8799"},
{name = "Corey Carbone", id = "6485"},
{name = "Conrad Theberge", id = "139"},
{name = "Arnulfo Oquendo", id = "2861"},
{name = "Damien Balsley", id = "5572"},
{name = "Efren Sloop", id = "7106"},
{name = "Blair Clagon", id = "614"},
{name = "Dario Service", id = "1411"},
{name = "Paul Ashalintubbi", id = "3403"},
{name = "Felix Veal", id = "1539"},
{name = "Laurence Caskey", id = "2827"},
{name = "Will Ranallo", id = "8463"},
{name = "Thomas Brenner", id = "9599"},
{name = "Claudio Hallmark", id = "6265"},
{name = "Nolan Haslett", id = "9661"},
{name = "Lenard Pereira", id = "5652"},
{name = "Dusty Duer", id = "4034"},
}
--
function countStringOccurence(query, itemList)
query = string.lower(query)
--if query string is found, store index of the itemList in table searchResult
local searchResult = {}
for i, item in ipairs(itemList) do
local name = string.lower(item.name)
if string.find(name, query) then
table.insert(searchResult, i)
end
end
--return both the occurence count and the list of found item
return #searchResult, searchResult
end
--execute the function
count, foundItemList = countStringOccurence("thomas", itemList)
--print results
print(count) --> 2
for i, index in ipairs(foundItemList) do
print(index, itemList[index].name) --> 4 Thomas Hemming
--> 26 Thomas Brenner
end
NB: Please note that if your table/list entries might be moved around (e.g. sort), it might not be advisable to just store the array index because the references/values collected in foundItemList might become incorrect.
Just don't stop iterating over the table once you found something. Keep on going and increment a counter variable every time you find your string or put your results into a table and count its elements later.
local texts = {"a123", "b213", "a332", "d411", "a124"}
local result = {}
for i,v in ipairs(texts) do
if string.find(v, "a") then
table.insert(result, v)
end
end
print(#result)
I'm using F# alongside a JSON data-store making use of the JSON.NET library. I'm trying to utilise F# structures and types where possible and have run into the following issue. Say I wish to store the following data structure,
type A = {
id : int
name : string
posts : string list
}
Creation works fine, but to update just the stored name field I need to send a JSON record that omits the posts field. Using the empty list won't work as the persistence system will assume that I wish to replace the existing posts with an empty list and thus overwrite them. From the JSON.NET docs I've read a field can be omitted from serialisation by setting it to null,
let updatedEntry = { id : 0, name : "Fred", posts = null }
However the F# compiler will give an error stating that the type list can not be set to null. Is there anyway to accomplish this from within F#, perhaps an attribute I'm unaware of? Thanks
There are two ways you could do this easily:
Option 1
Use the System.Collections.Generic.List type, which can be null:
> type A = {id: int; name:string; posts: System.Collections.Generic.List<string> };;
type A =
{id: int;
name: string;
posts: System.Collections.Generic.List<string>;}
> let a = {id=5; name="hello"; posts=null};;
val a : A = {id = 5;
name = "hello";
posts = null;}
Option 2
The other, more idiomatic way, would be to use the Option type:
> type A = {id: int; name:string; posts: string list option };;
type A =
{id: int;
name: string;
posts: string list option;}
> let a = {id=5; name="there"; posts=None};;
val a : A = {id = 5;
name = "there";
posts = null;}
Note that you'd compare the posts member to None rather than null.
Handy reading: Option types
Edit
(After some searching & experimentation) you could use boxing to still use F# types as the values:
> type A = {id: int; name:string; posts: System.Object };;
type A =
{id: int;
name: string;
posts: Object;}
> let a = {id=5; name="foo"; posts=null};;
val a : A = {id = 5;
name = "foo";
posts = null;}
> let b = {id=6; name="bar"; posts=(box [])};;
val b : A = {id = 6;
name = "bar";
posts = [];}
But I'd stick with the Option type, personally
I have created a set of search results, and I wish to create a filter of available cats, with the number of results within that filter. however I get the most strangest error when trying to do this.
Unable to create a constant value of type 'NAMESPACE.Models.Products'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
this is the code i have tried:
var cats = (from p in ctx1.SubCategories
where myCats.Contains(p.subCategoryId) && p.enabled
select new
AvailableSubCats
{
CategoryName = p.subCategoryName,
Id = p.subCategoryId,
TotalItems = model.Count(x => x.subCategoryId == p.subCategoryId)
}).Distinct();
Products is the object that is called model on the line of totalItems.
I have also tried this:
var cats = from c in ctx1.SubCategories
join p in model on c.subCategoryId equals p.subCategorySubId
group p by c.subCategoryName
into g
select new
AvailableSubCats
{
CategoryName = g.Key,
Id = 0,
TotalItems = g.Count()
};
with the same error, and dont like this because i dont know how to get the name of the category and its ID.
help much appreciated.
thanks
p.s I am using Entity framework 4.1, .net 4 and MVC 3, mysql
in short i am trying to run this in linq, but were the the products side is already a result
select c.*, (select count(productId) from Products where Products.subCategoryId = c.subCategoryId) as counter from SubCategories c
You could try turning your list of products into a list of subCategoryId's so EF can understand it. Something like:
var subCategoryIds = model.Select(m => m.subCategoryId);
var cats = (from p in ctx1.SubCategories
ctx1.SubCategories
where myCats.Contains(p.subCategoryId) && p.enabled
select new
AvailableSubCats
{
CategoryName = p.subCategoryName,
Id = p.subCategoryId,
TotalItems = subCategoryIds.Count(x => x == p.subCategoryId)
}).Distinct();