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).
Related
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.
I am trying to write a function that subString : string * string -> int
that checks if the first string is a substring of the second and its case sensitive.
I want to return the index starting from 0 if the first string is a substring or -1 if it is not. if it appears multiple times just return the index of the first appearance.
for instance:
subString("bc","abcabc") ===>1
subString("aaa","aaaa") ===>0
subString("bc","ABC") ===>-1
I am having a lot of trouble wrapping my brain around this because I am not too familiar with sml or using strings in sml and I am not supposed to use any built in functions like String.sub.
I can use helper functions though.
all I can think of is to use explode somehow in a helper function and somehow check the lists and then implode them, but how do I get the indexed position?
all I have is
fun subString(s1,s2) =
if null s2 then ~1
else if s1 = s2 then 0
else 1+subString(s1, tl s2);
I am thinking of using a helper function that explodes the strings and then maybe compares the two but I can't figure how to get that to work.
This is already a really good start, but there are some slight problems:
In your recursive case you add 1 to the recursive result, even if the recursive application did not find the substring and returned -1. You should check wether the result is -1 before adding 1.
In the second line you check whether the two strings are equal. If you do this you will only find a substring if the string ends with that substring. So what you really want to do in line 2 is to test whether s2 starts with s1. I would recommend that you write a helper function that performs that test. For this helper function you could indeed use explode and then recursively check whether the first character of the lists are identical.
Once you have this helper function use it in line 2 instead of the equality test.
I am not supposed to use any built in functions like String.sub
What a pity! Since strings have an abstract interface while you with lists have direct access to its primary constructors, [] and ::, you have to use library functions to get anywhere with strings. explode is also a library function. But okay, if your constraint is that you have to convert your string into a list to solve the exercise, so be it.
Given your current code,
fun subString(s1,s2) =
if null s2 then ~1
else if s1 = s2 then 0
else 1+subString(s1, tl s2);
I sense one problem here:
subString ([#"b",#"c"], [#"a",#"b",#"c",#"d"])
~> if null ([#"a",#"b",#"c",#"d"]) then ... else
if [#"b",#"c"] = [#"a",#"b",#"c",#"d"] then ... else
1 + subString([#"b",#"c"], [#"b",#"c",#"d"])
~> 1 + subString([#"b",#"c"], [#"b",#"c",#"d"])
~> 1 + if null ([#"b",#"c",#"d"]) then ... else
if [#"b",#"c"] = [#"b",#"c",#"d"] then ... else
1 + subString([#"b",#"c"], [#"c",#"d"])
It seems that the check s1 = s2 is not exactly enough: We should have liked to say that [#"b",#"c"] is a substring of [#"b",#"c",#"d"] because it's a prefix of it, not because it is equivalent. With s1 = s2 you end up checking that something is a valid suffix, not a valid substring. So you need to change s1 = s2 into something smarter.
Perhaps you can build a helper function that determines if one list is a prefix of another and use that here?
As for solving this exercise by explodeing your strings into lists: This is highly inefficient, so much that Standard ML's sister language Ocaml had explode entirely removed from the library:
The functions explode and implode were in older versions of Caml, but we omitted them from OCaml because they encourage inefficient code. It is generally a bad idea to treat a string as a list of characters, and seeing it as an array of characters is a much better fit to the actual implementation.
So first off, String.isSubstring already exists, so this is a solved problem. But if it weren't, and one wanted to write this compositionally, and String.sub isn't cheating (it is accessing a character in a string, comparable to pattern matching the head and tail of a list via x::xs), then let me encourage you to write efficient, composable and functional code:
(* Check that a predicate holds for all (c, i) of s, where
* s is a string, c is every character in that string, and
* i is the position of c in s. *)
fun alli s p =
let val stop = String.size s
fun go i = i = stop orelse p (String.sub (s, i), i) andalso go (i + 1)
in go 0 end
(* needle is a prefix of haystack from the start'th index *)
fun isPrefixFrom (needle, haystack, start) =
String.size needle + start <= String.size haystack andalso
alli needle (fn (c, i) => String.sub (haystack, i + start) = c)
(* needle is a prefix of haystack if it is from the 0th index *)
fun isPrefix (needle, haystack) =
isPrefixFrom (needle, haystack, 0)
(* needle is a substring of haystack if is a prefix from any index *)
fun isSubstring (needle, haystack) =
let fun go i =
String.size needle + i <= String.size haystack andalso
(isPrefixFrom (needle, haystack, i) orelse go (i + 1))
in go 0 end
The general idea here, which you can re-use when building an isSubstring that uses list recursion rather than string index recursion, is to build the algorithm abstractly: needle being a substring of haystack can be defined in simpler terms by needle being the prefix of haystack counting from any valid position in haystack (of course not such that it exceeds haystack). And determining if something is a prefix is much easier, even easier with list recursion!
This suggestion would leave you with a template,
fun isPrefix ([], _) = ...
| isPrefix (_, []) = ...
| isPrefix (x::xs, y::ys) = ...
fun isSubstring ([], _) = ...
| isSubstring (xs, ys) = ... isPrefix ... orelse ...
As for optimizing the string index recursive solution, you could avoid the double bounds checking in both isPrefixFrom and in isSubstring by making isPrefixFrom a local function only accessible to isPrefix and isSubstring; otherwise it will be unsafe.
Testing this,
- isSubstring ("bc", "bc");
> val it = true : bool
- isSubstring ("bc", "bcd");
> val it = true : bool
- isSubstring ("bc", "abc");
> val it = true : bool
- isSubstring ("bc", "abcd");
> val it = true : bool
- isSubstring ("bc", "");
> val it = false : bool
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 " ".
When I use sub_string("abberr","habberyry") , it returns True, when obviously it should be False. The point of the function is to search for the first argument within the second one. Any ideas what's wrong?
sub_string :: (String, String) -> Bool
sub_string(_,[]) = False
sub_string([],_) = True
sub_string(a:x,b:y) | a /= b = sub_string(a:x,y)
| otherwise = sub_string(x,y)
Let me give you hints on why it's not working:
your function consumes "abber" and "habber" of the input stings on the initial phase.
Now "r" and "yry" is left.
And "r" is a subset of "yry". So it returns True. To illustrate a more simple example of your problem:
*Main> sub_string("rz","rwzf")
True
First off, you need to switch your first two lines. _ will match [] and this will matter when you're matching, say, substring "abc" "abc". Secondly, it is idiomatic Haskell to write a function with two arguments instead of one with a pair argument. So your code should start out:
substring :: String -> String -> Bool
substring [] _ = True
substring _ [] = False
substring needle (h : aystack)
| ...
Now we get to the tricky case where both of these lists are not empty. Here's the problem with recursing on substring as bs: you'll get results like "abc" being a substring of "axbxcx" (because "abc" will match 'a' first, then will look for "bc" in the rest of the string; the substring algorithm will then skip past the 'x' to look for "bc" in "bxcx", which will match 'b' and look for "c" in "xcx", which will return True.
Instead your condition needs to be more thorough. If you're willing to use functions from Data.List this is:
| isPrefixOf needle (h : aystack) = True
| otherwise = substring needle aystack
Otherwise you need to write your own isPrefixOf, for example:
isPrefixOf needle haystack = needle == take (length needle) haystack
As Sibi already pointed out, your function tests for subsequence. Review the previous exercise, it is probably isPrefixof (hackage documentation), which is just a fancy way of saying startsWith, which looks very similar to the function you wrote.
If that is not the previous exercise, do that now!
Then write sub_string in terms of isPrefixOf:
sub_string (x, b:y) = isPrefixOf ... ?? ???
Fill in the dots and "?" yourself.
I need to write a method in Scala that overrides the toString method. I wrote it but I also have to check that if there is an element that is '1' I will change it to 'a', else write the list as it is with the string method. Any suggestions how this can be done?
What error are you getting? seems to work for me
val l = List(1, 2, 3)
println(this)
override def toString(): String = {
val t = l.map({
case 1 => "a"
case x => x
})
t.toString
}
getting List(a, 2, 3) printed out
I see from the comments on your question that list is a List[List[Int]].
Look at the beginning of your code:
list.map { case 1 => 'a'; case x => x}
map expects a function that takes an element of list as a parameter - a List[Int], in your case. But your code works directly on Int.
With this information, it appears that the error you get is entirely correct: you declared a method that expects an Int, but you pass a List[Int] to it, which is indeed a type mismatch.
Try this:
list.map {_.map { case 1 => 'a'; case x => x}}
This way, the function you defined to transform 1 to a and leave everything else alone is applied to list's sublists, and this type-checks: you're applying a function that expects an Int to an Int.