Elixir - Convert a string number or empty string to a float or nil - ecto

I am trying to convert the price field, which is a string (eg "2.22" or "") to a float or nil, and then add it to the database.
def insert_product_shop(conn, product_id, shop_id, price) do
priceFloat = nil
if price not in [""] do
price = elem(Float.parse(price), 0)
priceFloat = price / 1
IO.inspect(priceFloat)
else
priceFloat = nil
end
IO.inspect(priceFloat)
changeset = Api.ProductShop.changeset(%Api.ProductShop{
p_id: product_id,
s_id: shop_id,
price: priceFloat,
not_in_shop_count: 0,
is_in_shop_count: 0
})
errors = changeset.errors
valid = changeset.valid?
IO.inspect(changeset)
case insert(changeset) do
{:ok, product_shop} ->
{:ok, product_shop}
{:error, changeset} ->
{:error, :failure}
end
end
the output is:
2.22
nil
#Ecto.Changeset<action: nil, changes: %{}, errors: [], data: #Api.ProductShop<>,
valid?: true>
13:25:41.745 [debug] QUERY OK db=2.0ms
INSERT INTO "product_shops" ("is_in_shop_count","not_in_shop_count","p_id","s_id") VALUES ($1,$2,$3,$4) RETURNING "id" [0, 0, 40, 1]
As the output shows, priceFloat becomes nil, I assume because when I set it to 2.22 it was out of scope. Maybe my code is too imperative. How can I rewrite this to convert "2.22" to 2.22 without making it nil, and allow "" to be converted to nil?

As the output shows, priceFloat becomes nil, I assume because when I set it to 2.22 it was out of scope.
Almost right. Rather that the variable you are trying to set being out of scope, the problem is that the variable you assign to inside the if statement goes out of scope. It just happens to have the same name as the variable outside the if statement.
The solution is to assign the result of the if/else statement to the variable. Here is your code with minimal changes:
price = "2.22"
priceFloat =
if price not in [""] do
elem(Float.parse(price), 0)
else
nil
end
IO.inspect(priceFloat)
However, it's still not very idiomatic. You can take advantage of the fact that Float.parse/1 returns :error when the input is the empty string to write it like with a case expression:
priceFloat =
case Float.parse(price) do
{float, ""} -> float
:error -> nil
end

You can use case to evaluate the returned value by Float.parse and assign nil when it returns :error, assuming that the purpose of your if is to avoid the parsing error
def insert_product_shop(conn, product_id, shop_id, price) do
priceFloat = case Float.parse(price) do
{value, _remainder} -> value
:error -> nil
end
...
end

You can use a combination of pattern matching and method overloading to solve the problem:
defmodule Example do
def parsePrice(""), do: nil
def parsePrice(price) when is_float(price), do: price
def parsePrice(price) when is_binary(price) do
{float, _} = Float.parse(price)
float
end
end
Example.parsePrice(2.22) |> IO.inspect
Example.parsePrice("2.22") |> IO.inspect
(The equivalent is achievable using a case statement)
If you pass anything that is not a binary (a string) or a float to this function it will cause a pattern unmatched error. This may be good in case you have some error reporting in place, so you can detect unexpected usage of your code.
For a better debugging experience, I encourage you to use the built-in debugger via IEx.pry/0.

For the sake of diversity, I’d post another approach that uses with/1 special form.
with {f, ""} <- Float.parse("3.14"),
do: f,
else: (_ -> nil)
Here we explicitly match the float only. Any trailing garbage would be discarded. If the match succeeds, we return the float, otherwise, we return nil.
Beware of Float.parse/1 might be confused by garbage that looks like scientific notation.
(with {f, ""} <- Float.parse("3e14"), do: f) == 300_000_000_000_000
#⇒ true
Important sidenote: assigning priceFloat inside if does not change the value of the priceFloat variable outside of the scope. Scoping in elixir is pretty important and one cannot propagate local variables to the outermost scope, unlike most of the languages.
foo = 42
if true, do: foo = 3.14
IO.puts(foo)
#⇒ 42
Well, to some extent it’s possible to affect outermost scope variables from macros with var!/2, and if is indeed a macro, but this whole stuff is definitely far beyond the scope of this question.

Related

OCaml Test if a string is almost empty or contains keywords

I've got a problem in OCaml, I'm currently learning it but I'm quite a newbie still. I would like to make a function which is returning true if the string is empty or contains only whitespace and in the same time remove any occurence of begin and end.
I tried already this:
let isEmptyString s =
let rec empty i =
if i < 0 then true
else
let c = String.get s i in
if c = ' ' || c = '\009' then empty (pred i)
else false
in
s = Str.global_replace( Str.regexp "begin") "" s;
s = Str.global_replace( Str.regexp "end") "" s;
empty (pred (String.length s))
But obviously, this function is not working as I would like it because I obtain still begin in Formula.importNrAgentsFormula after calling it... Here is my way to call it :
while true do
let input = read_line () in
if not (isEmptyString input) then
let (nr, f) = Formula.importNrAgentsFormula input in
incr counter;
flush stdout;
match choice with
| "graph" -> printRes (Graph.isSat ~verbose:verb nr f)
| _ -> printUsage ()
else ()
done
If someone with more experiences in OCaml could spot and explain to me the error, I would be glad :)
Thanks in advance,
Best Regards.
I suggest you let your function isEmptyString (isBlankString rather?) do what it is supposed to do (just check if it contains only whitespaces or nothing), it should not modify the original string. You can do this in your loop:
while true do
let input = read_line () in
let input = Str.global_replace( Str.regexp "begin") "" input in
let input = Str.global_replace( Str.regexp "end") "" input in
if not (isEmptyString input) then
...
Edit: Sorry for the late edit, here is some additional information on your error:
If you run your function in OCaml, you will see this warning:
Warning 10: this expression should have type unit.
on the line of s = Str.global_replace( Str.regexp "begin") "" s;. That is because the = operator in OCaml is not the assignment operator in this case but the equality operator, so on this line you simply compare your two values and return a boolean. Since OCaml expects e1 in e1;e2 to return unit, you get this warning.
In OCaml, values of variables are immutable, so you can:
Use another variable as #Jason suggests: let t = Str.global_replace( Str.regexp "begin") "" s
"shadow" the old value as I suggest above: let s = Str.global_replace( Str.regexp "begin") "" s
Use a reference (a pointer to a location in memory): let s = ref "before" in s := "after", you can then access the value pointed by the reference with the !operator: !s. However, if you are learning functional programming, I suggest you try not to use any imperative features of OCaml at the beginning to discover this new paradigm and its possibilities.
As I am at work I don't have utop with me, but just from first glance, in your first one, the documentation says:
val global_replace : regexp -> string -> string -> string
That means you don't need a ";" as that is for when functions return unit and is syntactic sugar for something like
let () = print_endline("foobar")
Additionally, you need to use a let statement as you cannot just reassign the value of s. I don't recommend shadowing the variable as that's generally bad practice in functional programming. Use something like:
let t = (Str.global_replace( Str.regexp "begin") "" s)
Also, your function does two different things. The helper recursive function you wrote returns true and false which is good (I'm assuming it works). What you ultimately use it for however is what you're returning. Therefore, for the first function are you aren't really returning the string if "begin" and "end"s have been replaced. Therefore you should have the end output of your function actually a tuple of type (bool,string). Then you can match on it when you call it (e.g.
let b,s = isEmptyString "foobar" in
if not b then:
rest of your code
I believe you have the right idea for your function though.
Also in your second function is there a way for you to not use any while loops and counters? (Also hopefully your counter is implemented with references otherwise you won't have anything global). I would suggest retrying the place where you call your first function as loops and counters are core to imperative programming and not functional (which is what makes OCaml so
fun
:). If not, it's fine sometimes there are just things you can't really do in OCaml without using its imperative features. Let me know if those suggestions don't work.

Split a string into an Array in Swift

I'm trying to write my first Swift program, and I know this question has been asked before, but the answers using split aren't working for me. I'm using Xcode 6.4 and Swift 1.2.
I have a String named line.
If I write
let inputs = split(line) {$0 = " "}
as suggested at Swift: Split a String into an array, I get the error message "Cannot invoke 'split' with an argument list of type (String, ()->)"
If I write
let inputs = split(line, {find(" ",$0) != nil}, allowEmptySlices: false)
as suggested at split now complains about missing "isSeparator", I get the error message, "Missing argument for parameter 'isSeparator' in call."
If I jump to the definition of split, I find
func split<S : Sliceable, R : BooleanType>(elements: S, maxSplit: Int = default, allowEmptySlices: Bool = default, #isSeparator: #noescape (S.Generator.Element) -> R) -> [S.SubSlice]
I don't understand what the type of the last parameter is, which is perhaps the root of my problem. Can you tell me how I should call split, and even better can you explain what the parameter type is? Why isn't the type simply (S)->R? I am getting the line from a generator that reads a file line-by-line, if that makes any difference.
for line:String in reader! {
let inputs = split(line) {$0 = " "}
...
}
As said in the comments to the question, the correct way is to use the == operator instead of =.
The type (S.Generator.Element) -> R) must be interpreted in the light of the definition of split:
func split<S : Sliceable, R : BooleanType>
(elements: S,
maxSplit: Int = default,
allowEmptySlices: Bool = default,
#isSeparator: #noescape (S.Generator.Element) -> R)
-> [S.SubSlice]
The type of split is a generic one: in other words, it is a function that can take as first parameter any value that satisfy a generic type (or protocol) subtype of Sliceable, like String, and return a result which must be a subtype of BooleanType (for instance true or false, which are instances of Bool). So the last parameter is a function which gets as parameter a type which is Element of Generator of S (for instance Character) and returns a value of type R. And {$0 == " "} is exactly a predicate of this type, that has an (implicit) parameter ($0), and check if it is equal to the character " ".

Scala Filter Chars from String

I've got the following code which is supposed to count the numbers of times a character appears in a string.
def filter[T] (l: List[T], stays: T ⇒ Boolean): List[T] = {
if( l == Nil ) return Nil
if (stays(l.head) == true) l.head :: filter(l.tail, stays)
else filter(l.tail, stays)
}
def countChar(s: String): List[(Char, Int)] = {
if (s == "") Nil
else (s(0), s.count(_ == s(0))) :: countChar(filter(s.toList, _ == s(0)).mkString)
}
Now my problem is that in
filter(s.toList, _ == s(0))
I get the error of: missing parameter type. I understand that this comes from nesting the function?
How can I fix this to work? I know that String has some methods to do what I want but I'd like to use my own filter method.
That's a limitation of Scala compiler: it tries to figure out what type T in filter should be, using both arguments l and stays. But it fails because the type of stays argument is unspecified.
If you don't want to specify the type of stays argument every time (i.e., filter(s.toList, (_: Char) == s(0)), you can split filter's argument list into two:
def filter[T] (l: List[T])(stays: T ⇒ Boolean): List[T]
Then Scala will know that T is Char by the time it analyzes the type of stays. You can call this filter with filter(l.tail)(stays).

Most efficient interval type search in Elixir

I am starting my journey with Elixir and am looking for some advice on how best to approach a particular problem.
I have a data set that needs to be searched as quickly as possible. The data consists of two numbers that form an enclosed band and some meta data associated with each band.
For example:
From,To,Data
10000,10999,MetaData1
11000,11999,MetaData2
12000,12499,MetaData3
12500,12999,MetaData4
This data set could have upwards of 100,000 entries.
I have a struct defined that models the data, along with a parser that creates an Elixir list in-memory representation.
defmodule Band do
defstruct from: 0, to: 0, metadata: 0
end
The parser returns a list of the Band struct. I defined a find method that uses a list comprehension
defp find_metadata(bands, number) do
match? = fn(x) -> x.from <= number and x.to >= number end
[match | _ ] = for band <- bands, match?.(band), do: band
{ :find, band }
end
Based on my newbie knowledge, using the list comprehension will require a full traversal of the list. To avoid scanning the full list, I have used search trees in other languages.
Is there an algorithm/mechanism/approach available in Elixir that would a more efficient approach for this type of search problem?
Thank you.
If the bands are mutually exclusive you could structure them into a tree sorted by from. Searching through that tree should take log(n) time. Something like the following should work:
defmodule Tree do
defstruct left: nil, right: nil, key: nil, value: nil
def empty do
nil
end
def insert(tree, value = {key, _}) do
cond do
tree == nil -> %Tree{left: empty, right: empty, key: key, value: value}
key < tree.key -> %{tree | left: insert(tree.left, value)}
true -> %{tree | right: insert(tree.right, value)}
end
end
def find_interval(tree, value) do
cond do
tree == nil -> nil
value < tree.key -> find_interval(tree.left, value)
between(tree.value, value) -> tree.value
true -> find_interval(tree.right, value)
end
end
def between({left, right}, value) do
value >= left and value <= right
end
end
Note that you can also use Ranges to store the "bands" as you call them. Also note that the tree isn't balanced. A simple scheme to (probably) achieve a balanced tree is to shuffle the intervals before inserting them. Otherwise you'd need to have a more complex implementation that balances the tree. You can look at erlang's gb_trees for inspiration.

Type Problems chaining CaseOf Statements with Parsec

I'm learning haskell, and my current project is writing a parser to read a text file representation of a database.
At the moment, I'm setting up the code for reading individual fields of tables. In the text file, fields look either like this:
name type flags format
or this:
name type format
This gives the trouble of having to account for cases of there being a flag or not being a flag. I solved this in my main function like this:
main = case parse fieldsWithFlags "(test)" testLine of
Left err -> noFlags
Right res -> print res
where noFlags = case parse fieldsWithoutFlags "(test)" testLine of
Left err -> print err
Right res -> print res
If I understand correctly, this says "If it's a line that doesn't have flags, try to parse it as such; otherwise, return an error." It prints the correct results for any "testLine" I throw at it, and returns errors if both options fail. However, when I try to pull this out into its own function, like this:
field :: Either ParseError Field
field = case parse fieldsWithFlags "(test)" testLine of
Left err -> noFlags
Right res -> return Right res
where noFlags = case parse fieldsWithoutFlags "(test)" testLine of
Left err -> return Left err
Right res -> return Right res
main = case field of
Left err -> print err
Right res -> print res
GHC gives me:
haskellParsing.hs:58:26:
Couldn't match expected type `Either ParseError Field'
with actual type `b0 -> Either b0 b0'
In the expression: noFlags
In a case alternative: Left err -> noFlags
In the expression:
case parse fieldsWithFlags "(test)" testLine of {
Left err -> noFlags
Right res -> return Right res }
I've played around with this a lot, but just can't get it working. I'm sure there's a much more clear-headed way of doing this, so any suggestions would be welcome - but I also want to understand why this isn't working.
Full code is at: http://pastebin.com/ajG6BkPU
Thanks!
You don't need the return in your cases. Once you wrap something in Left or Right it is in Either; since you only need a Either ParseError Field, the Left and Right do not need an extra return.
Also, you should be able to simplify your parseFields significantly. You can write a new parser that looks like this:
fields = try fieldsWithFlags <|> fieldsWithoutFlags
what this does is run the first one and, if it fails, backtrack and run the second one. The try is important because this is what enables the backtracking behavior. You have to backtrack because fieldsWithFlags consumes some of the input that you care about.
Now you should be able to just use fields in your main function.
Since the form without flags is almost identical to that with flags (just that the flags are missing), the alternative can be pushed down to where the flags might appear. In this way, you avoid backtracking over name and type in with-flags, just to parse them again in without-flags. We could combine the with and without fields parsers like this:
fields = do
iName <- getFieldName
spaces
iType <- getDataType
spaces
iFlag <- option "" $ try getFlag
spaces
iFormat <- getFormat
newline -- this was only present in without flags, was that intended?
return $ Field iName iType iFlag iFormat

Resources