ChargerIIC
ChargerIIC

Reputation: 1690

Need to test string for instance of words from list in F#

I have a list of words in F# and a string input. I want to see if any of the words in the list are contained in the string. If I was using C# Id run a foreach loop on each word in the string.split and run an List.contains comparison. I have come up with the following code so far, but can't seem to access List.contains on the value 'str'

 let checkforvalue(x:string) = 
  for str in x.Split(' ') do
    match str with commandList -> Console.WriteLine(str + " found: " + x)
  ()

The current function always returns true and executes the Console.WriteLine method.

Any ideas what I am doing wrong?

Upvotes: 1

Views: 714

Answers (3)

MisterMetaphor
MisterMetaphor

Reputation: 6008

I think you have misunderstood the semantics of the pattern matching syntax. The match str with commandList will not go through the commandList and see if str 'matches' any of the strings in commandList.

Instead, it will try to destructure str into a pattern that you provide, which in your case says nothing about the actual structure, so anything will effectively be matched and bound to the name commandList.

As @JohnPalmer pointed out, this will just shadow your other commandList binding. But anyway, I don't think pattern matching is a proper way to solve your problem, even (especially?) if you go as far as using Active Patterns.

Here's how you could solve this problem instead:

let checkForValue (str : string) commandList =
    // convert to set for better performance
    let commands = Set.ofList commandList
    str.Split(' ') |> Seq.exists (fun x -> Set.contains x commands)

Upvotes: 2

Daniel
Daniel

Reputation: 47904

This doesn't answer your question directly, but you're essentially doing set intersection, which can be expressed more simply:

Set.intersect (set (x.Split(' '))) (set commandList)

Upvotes: 6

John Palmer
John Palmer

Reputation: 25516

The problem here is that commandList when used how you have used it creates a new variable which shadows the old.

You probably want something like

let checkforvalue(x:string) = 
  for str in x.Split(' ') do
    match str with s when s=commandList -> Console.WriteLine(str + " found: " + x)

if commandList is a string

If it is a list you could do:

let checkforvalue(x:string) = 
  for str in x.Split(' ') do
    if List.exists (fun s -> s=str) commandlist then Console.WriteLine(str + " found: " + x)

Upvotes: 2

Related Questions