Racket: Apply string-replace to list - functional-programming

(apply string-replace ";" "" '("a" "b;" "c"))
gives me the error message
string-replace: arity mismatch;
the expected number of arguments does not match the given number
expected: 3 plus an optional argument with keyword #:all?
given: 5
arguments...:
As far as I understand, the problem is that the list is consed to the arguments of the string-replace function, whereas I would like to apply the function to every element of the list.
What would be the correct way to apply string-replace to a list?
(apply string-replace "b" "" '("b;"))
works, but returns "b;bb; whereas I would have expected "b".

To apply a function to all the elements of a list, use map (reference):
(map (lambda (str) (string-replace str ";" ""))
'("a" "b;" "c"))
produces
'("a" "b" "c")

Related

Loop through a list of values, find matches in keys and sum matched values in Elixir

I'm learning Elixir and I'm having a difficulty with this simple problem:
I have a list of values:
my_list = ["a", "b", "c", "y", "z", "a", "e"]
And I have a map:
my_map = %{"a" => -1, "b" => 0, "c" => 1, "d" => 2, "e" => 3}
I want to loop through my_list, find all key occurrences in my_map and sum the values from my_map if the occurrence happened.
In the above example it should return 2 because:
-1 + 0 + 1 + (ignored) + (ignored) - 1 + 3
# => 2
This is a very easy thing to do in languages with mutable variables (we can loop the list and add a counter). I'm working on changing my mindset.
Thank you for help!
I'm working on changing my mindset.
Admirable. You'll find great success in Elixir if you're willing to change your mindset and try to think more functionally. With that in mind, let's break the problem down.
I want to loop through my_list
More precisely, you want to do something to each element of the list and get a list of the results. That's Enum.map/2.
Enum.map(my_list, fn x -> ...)
Now, ... needs to be replaced with what we want to do to each list element. We want to get the corresponding map elements, ignoring those that are not present. Since we're taking a sum, "ignoring" really just means "replacing with zero". Map.get/3 can get a value from a map, using a default if not provided.
Enum.map(my_list, fn x -> Map.get(my_map, x, 0) end)
Now, we have a list of numbers. We just want the sum. That could be done in terms of Enum.reduce/3, but summing is a common enough task that it has its own function: Enum.sum/1.
Enum.sum(Enum.map(my_list, fn x -> Map.get(my_map, x, 0) end))
Finally, this reads backwards. It says "sum the result of mapping over the list", when it would read much cleaner as "take the list, get the elements from the map, then take a sum". We can clean it up with the pipe operator. The following is equivalent to the above.
my_list |> Enum.map(fn x -> Map.get(my_map, x, 0) end) |> Enum.sum
This is a nice use case for a comprehension:
for key <- my_list, val = my_map[key], reduce: 0 do
acc -> acc + val
end
Here the val = my_map[key] is a filter. When key is not in my_map, the result will be nil, which is a falsy value so is skipped.
While both answers given here are perfectly valid, I’m to post another one using plain recursion, for the sake of completeness.
defmodule Summer do
def consume(list, map, acc \\ 0) # head
def consume([], _, acc), do: acc # exhausted
def consume([h | t], map, acc) when is_map_key(map, h),
do: consume(t, map, acc + Map.fetch!(map, h))
def consume([_h | t], map, acc), do: consume(t, map, acc)
end
Summer.consume my_list, my_map
#⇒ 2

How to create and add items to dictionary

I am trying to create a dictionary or hash-table where keys are string and values are integers with following code:
(define dict #())
(dict-set! dict "bash" 1)
(displayln dict)
(dict-set! dict "racket" 1)
(displayln dict)
However, it gives following error:
dict-set!: contract violation
expected: (dict-implements/c dict-set!)
given: '#()
in: the d argument of
(->i
((d (dict-implements/c dict-set!))
(k (d) (dict-key-contract d))
(value (d) (dict-value-contract d)))
(_r void?))
contract from: <collects>/racket/dict.rkt
Where is the problem and how can it be solved?
The problem is that the literal #() is an empty vector.
To make a mutable hash table, use (make-hash).
(define dict (make-hash))

trying to use cl-lexer on a file containing "{" and "}"

Using the file "test-lexer.lisp", I have very slightly modified lex to be
(defparameter *lex* (test-lexer "{ 1.0 12 fred 10.23e12"))
and increased the number of times test repeats to 6
(defun test ()
(loop repeat 6
collect (multiple-value-list (funcall *lex*))))
and tried modifying test-lexer in a number of ways to try to get it to recognize "{" as a token.
For example, adding [:punct:] in (deflexer test-lexer ...)
by changing
("[:alpha:][:alnum:]*"
(return (values 'name %0)))
to
("[:alpha:][:alnum:][:punct:]*"
(return (values 'name %0)))
and consistently get errors like
"""Lexer unable to recognize a token in "{ 1.0 12 fred 10.23e12", position 0 ("{ 1.0 12 fred 10.23e")
[Condition of type SIMPLE-ERROR]"""
How can i specify "{" as a character to be recognized? Or is my problem elsewhere?
The cl-lexer system is based on regular expressions, so you can put any literal character to stand for itself, like {. But it happens that the brace character has a special meaning in the regular expression language, so you need to quote it with a backslash. In order to write a backslash in Lisp strings, backslashes need to be escaped. Hence:
(deflexer test-lexer
("\\{" (return (values :grouping :open-brace))) ;; <-- Here
("[0-9]+([.][0-9]+([Ee][0-9]+)?)"
(return (values 'flt (num %0))))
("[0-9]+"
(return (values 'int (int %0))))
("[:alpha:][:alnum:]*"
(return (values 'name %0)))
("[:space:]+"))
I return the :open-brace value and the :grouping category, but you can choose to return something else if you want.
The test function then returns:
((:GROUPING :OPEN-BRACE) (FLT 1.0) (INT 12)
(NAME "fred") (FLT 1.023e13) (NIL NIL))

Clojure: Apply a nested vector format to a flattened vector

For example, I have the following nested vector:
[[[0.582198689235419 -0.34713183143727 0.4685311493624731]
[-0.38928013774079284 -0.5901700383677557 -0.37573234072157]
[0.6716356761877877 -0.19645167952721243 -0.5700686091940252]]
[[0.0027162308840597005 -0.4483592764429284 -0.4766278022217257 -0.2724018313051576]
[-0.2765881229144672 -0.8030656496255356 -0.16159395457031567 -0.27432324260043084]
[-0.6154630466545907 -0.60573539482247 0.4417814561800192 -0.5559788990464504]
[0.6194560094536031 -0.3663074359460578 -0.5704311251195602 0.7194827876969362]]]
And I have the following flattened vector:
(0.5366343712173423
-0.816449781850872
-0.16066485785704843
0.9816561233924161
-0.09646744313584676
-0.2619662625757997
-0.9946004265996822
-0.14096299956754854
0.579260850612288
-0.827601452607939
-0.24934665032374648
-0.42272393175707873
0.11239245249400165
-0.29878238708035043
-0.61522274672097
0.8298721730401472
0.5016214138116059
0.11633537727916243
-0.0631891708267196
-0.26569217599364303
0.20900664784109668
0.2005869506108401
-0.2658279978034501
0.3383997403318165
-0.09353513546647907)
I want the flattened vector to be converted to a nested vector that follows the same structure as the nested vector presented above. Is there a core function in Clojure or a library that does this? I have some ideas of how to solve this problem, but all of them seem very very inefficient, and this operation will be used with big vectors.
Thank you very much in advance.
This was a fun question to answer, because it is one of the very few times when I think using a zipper makes things easier instead of harder. The idea is to just make a vector-zip of the nested vector, to represent the desired structure, and call zip/next on it repeatedly; whenever we get to a node which is a leaf, we replace its value with the next one from the input sequence.
Note that this assumes there are exactly as many items in the nested structure as in the flattened list; if that is not the case, you will probably get an error of some kind, who knows.
(require '[clojure.zip :as z])
(defn replace-values [structure values]
(loop [z (z/vector-zip structure)
values (seq values)]
(cond (not values) (z/root z)
(z/branch? z) (recur (z/next z) values)
:else (recur (-> z
(z/replace (first values))
(z/next))
(next values)))))
user> (replace-values '[[[0.582198689235419 -0.34713183143727 0.4685311493624731]
[-0.38928013774079284 -0.5901700383677557 -0.37573234072157]
[0.6716356761877877 -0.19645167952721243 -0.5700686091940252]]
[[0.0027162308840597005 -0.4483592764429284 -0.4766278022217257 -0.2724018313051576]
[-0.2765881229144672 -0.8030656496255356 -0.16159395457031567 -0.27432324260043084]
[-0.6154630466545907 -0.60573539482247 0.4417814561800192 -0.5559788990464504]
[0.6194560094536031 -0.3663074359460578 -0.5704311251195602 0.7194827876969362]]]
'(0.5366343712173423
-0.816449781850872
-0.16066485785704843
0.9816561233924161
-0.09646744313584676
-0.2619662625757997
-0.9946004265996822
-0.14096299956754854
0.579260850612288
-0.827601452607939
-0.24934665032374648
-0.42272393175707873
0.11239245249400165
-0.29878238708035043
-0.61522274672097
0.8298721730401472
0.5016214138116059
0.11633537727916243
-0.0631891708267196
-0.26569217599364303
0.20900664784109668
0.2005869506108401
-0.2658279978034501
0.3383997403318165
-0.09353513546647907))
[[[0.5366343712173423 -0.816449781850872 -0.16066485785704843]
[0.9816561233924161 -0.09646744313584676 -0.2619662625757997]
[-0.9946004265996822 -0.14096299956754854 0.579260850612288]]
[[-0.827601452607939 -0.24934665032374648 -0.42272393175707873 0.11239245249400165]
[-0.29878238708035043 -0.61522274672097 0.8298721730401472 0.5016214138116059]
[0.11633537727916243 -0.0631891708267196 -0.26569217599364303 0.20900664784109668]
[0.2005869506108401 -0.2658279978034501 0.3383997403318165 -0.09353513546647907]]]

Create a variable name from a string in Lisp

I'm trying to take a string, and convert it into a variable name. I though (make-symbol) or (intern) would do this, but apparently it's not quite what I want, or I'm using it incorrectly.
For example:
> (setf (intern (string "foo")) 5)
> foo
5
Here I would be trying to create a variable named 'foo' with a value of 5. Except, the above code gives me an error. What is the command I'm looking for?
There are a number of things to consider here:
SETF does not evaluate its first argument. It expects a symbol or a form that specifies a location to update. Use SET instead.
Depending upon the vintage and settings of your Common Lisp implementation, symbol names may default to upper case. Thus, the second reference to foo may actually refer to a symbol whose name is "FOO". In this case, you would need to use (intern "FOO").
The call to STRING is harmless but unnecessary if the value is already a string.
Putting it all together, try this:
> (set (intern "FOO") 5)
> foo
5
Use:
CL-USER 7 > (setf (SYMBOL-VALUE (INTERN "FOO")) 5)
5
CL-USER 8 > foo
5
This also works with a variable:
CL-USER 11 > (let ((sym-name "FOO"))
(setf (SYMBOL-VALUE (INTERN sym-name)) 3))
3
CL-USER 12 > foo
3
Remember also that by default symbols are created internally as uppercase. If you want to access a symbol via a string, you have to use an uppercase string then.

Resources