I see that there's an update in the Dict module, but what about an update_all method that changes all values?
I tried doing this with Enum.map but the type changed:
iex(6)> Enum.map(%{:a => 2}, fn {k, v} -> {k, v + 1} end)
[a: 3]
You could pipe to Enum.into(%{}) or use a for comprehension, i.e.:
iex> for {k, v} <- %{a: 1, b: 2}, into: %{}, do: {k, v + 1}
%{a: 2, b: 3}
You can also do:
iex> Map.new(%{:a => 2}, fn {k, v} -> {k, v + 1} end)
%{:a => 3}
But feel like there should be something in the standard library to make this easier (Map.??(%{:a => 2}, &(&1 + 1))).
Here's one idea:
def update_map map, [head|tail], func do
update_map(
Dict.update(map, head, :unknown, func),
tail,
func
)
end
def update_map map, [], _ do
map
end
Then to call it:
iex(1)> d = %{:a => 1, :b => 2, :c => 3}
%{a: 1, b: 2, c: 3}
iex(2)> update_map(d, Dict.keys(d), fn v -> v + 1 end)
%{a: 2, b: 3, c: 4}
Let me add Enum.into into the mix
headers
|> Enum.group_by(fn {k, _v} -> k end, fn {_k, v} -> v end)
|> Enum.into(%{}, fn {k, v} -> {k, Enum.join(v, ", ")} end)
This turns:
[{"cookie", "a"}, {"cookie", "b"}] into %{"cookie", "a, b"}
Related
find key : sum in nested map and update its value to : bill * 100 + : coins
Need to pass test1
test "test1" do
assert BcToInt.data(%{
count: 3,
sum: %{bills: 1, coins: 99},
tax: %{count: 3, sum: %{bills: 1, coins: 1}}
}) ==
%{count: 3, sum: 199, tax: %{count: 3, sum: 101}}
end
I tried to do it using Map_replace() and checking value for nested map using is_map and call function again if true but how to get end result
def data(xmap) do
Enum.map(xmap, fn {_key, value} ->
keyy = :sum
aa = List.first(Map.values(xmap[keyy])) * 100 + List.last(Map.values(xmap[keyy]))
if Map.has_key?(xmap, keyy) do
Map.replace(xmap, keyy, aa)
if is_map(value) do
data1(value)
end
end
end)
end
Here's a version without using external libraries:
def data(map) do
map =
case map[:sum] do
%{bills: bills, coins: coins} -> %{map | sum: bills * 100 + coins}
_ -> map
end
Map.new(map, fn
{k, v} when is_map(v) -> {k, data(v)}
entry -> entry
end)
end
Usage:
iex(1)> data = ...
%{
count: 3,
sum: %{bills: 1, coins: 99},
tax: %{count: 3, sum: %{bills: 1, coins: 1}}
}
iex(2)> BcToInt.data(data)
%{count: 3, sum: 199, tax: %{count: 3, sum: 101}}
With a help of iteraptor library:
Mix.install([:iteraptor])
Iteraptor.map(data, fn
{_k, %{bills: bills, coins: coins}} -> bills * 100 + coins
# Is not `bill:` a typo?
{_k, %{bill: bills, coins: coins}} -> bills * 100 + coins
other -> other
end, yield: :all)
#⇒ %{count: 3, sum: 199, tax: %{count: 3, sum: 101}}
Your implementation correctly uses recursion to look into nested data structures. It looks like it's trying to use Map.replace/3 to try to modify the data structure in place, though. Elixir only has immutable data structures, so you need to construct a new map from the input rather than trying to update it in place.
I might implement the recursion here using pattern matching:
def data(%{bills: bills, coins: coins}) do
bills * 100 + coins
end
def data(map) when is_map(map) do
Map.new(map, fn {k, v} -> {k, data(v)} end)
end
def data(any) do
any
end
With this setup, if data/1 is called with a map with the :bills and :coins keys (not necessarily in a field named :sum) it adds them together; on any other map, it recurses through the values preserving the keys; and on any other value it returns the original value as-is.
def data(xmap) do
keyy = :sum
aa = List.first(Map.values(xmap[keyy])) * 100 +
List.last(Map.values(xmap[keyy]))
Map.new(xmap, fn
{k, _v} when k == keyy -> {k, aa}
{k, v} when is_map(v) -> {k, data(v)}
{k, v} -> {k, v}
end)
end
Given Alice's triplet and Bob's triplet (lists), I need to compare each element so if alice_triplet[i] > bob_triplet[i], Alice's score is incremented by one, and vice versa.
I have this code:
def main do
alice_triplet = [5, 6, 7]
bob_triplet = [3, 6, 10]
alice_score = 0
bob_score = 0
Enum.zip(alice_triplet, bob_triplet)
|> Enum.each(fn
tuple when elem(tuple, 0) > elem(tuple, 1) -> alice_score = alice_score + 1
tuple when elem(tuple, 1) > elem(tuple, 0) -> bob_score = bob_score + 1
_ -> nil end)
IO.puts alice_score
IO.puts bob_score
end
But, the output is:
0
0
Why? I think it is about the variable scope because I'm getting this warning:
warning: variable "alice_score" is unused solution.ex:12
warning: variable "bob_score" is unused solution.ex:13
Is there a "more functional" way to do this? I'm learning Elixir (and FP in general, actually), so any advice will be appreciated.
The statement alice_score = alice_score + 1 does not modify the outer alice_score, it creates a new local alice_score with the value set to the outer value + 1. This has been covered in many answers. The solution almost always is to use Enum.reduce/3 with the state you need to change used as the accumulator.
Here's how that can be applied to your code:
alice_triplet = [5, 6, 7]
bob_triplet = [3, 6, 10]
{alice_score, bob_score} = Enum.zip(alice_triplet, bob_triplet) |>
Enum.reduce({0, 0}, fn
tuple, {as, bs} when elem(tuple, 0) > elem(tuple, 1) -> {as + 1, bs}
tuple, {as, bs} when elem(tuple, 1) > elem(tuple, 0) -> {as, bs + 1}
_, {as, bs} -> {as, bs}
end)
IO.puts alice_score
IO.puts bob_score
You can also simplify the code using pattern matching instead of elem/2 (elem/2 is rarely used in idiomatic Elixir code):
alice_triplet = [5, 6, 7]
bob_triplet = [3, 6, 10]
{alice_score, bob_score} = Enum.zip(alice_triplet, bob_triplet) |>
Enum.reduce({0, 0}, fn
{a, b}, {as, bs} when a > b -> {as + 1, bs}
{a, b}, {as, bs} when b > a -> {as, bs + 1}
_, {as, bs} -> {as, bs}
end)
IO.puts alice_score
IO.puts bob_score
The output in both cases is
1
1
Excuse me I am new to Wolfram. I have seen people asking questions about how to do convolution of a function with itself in Wolfram. However, I wonder how to do it multiple times in a loop. That is to say I want to do f20* i.e. f*f*f*f*....f totaling 20 f. How to implement it?
Here is my thinking. Of course do not work....
f[x_] := Piecewise[{{0.1`, x >= 0 && x <= 10}, {0, x < 0}, {0, x > 10}}];
g = f;
n = 19;
For[i = 1, i <= n, i++, g = Convolve[f[x], g, x, y]]; Plot[
g[x], {x, -10, n*10 + 10}, PlotRange -> All]
Could anybody help me?
My new code after revising agentp's code
f[x_] := Piecewise[{{0.1, x >= 0 && x <= 10}, {0, x < 0}, {0,x > 10}}];
n = 19;
res = NestList[Convolve[#, f[x], x, y] /. y -> x &, f[x], n];
Plot[res, {x, -10, (n + 1)*10 + 10}, PlotRange -> All,PlotPoints -> 1000]
My buggy image
maybe this?
Nest[ Convolve[#, f[x], x, y] /. y -> x &, f[x] , 3]
If that's not right maybe show what you get by hand for n=2 or 3.
res = NestList[ Convolve[#, f[x], x, y] /. y -> x &, f[x] , 10];
Plot[res, {x, 0, 100}, PlotRange -> All]
this gets very slow with n, I don't have the patience to run it out to 20.
Your approach is nearly working. You just have to
make sure to copy f by value before entering the loop, because otherwise you face infinite recursion.
Assign the result of Convolve to a function which takes a parameter.
This is the code with the mentioned changes:
f[x_] := Piecewise[{{0.1, x >= 0 && x <= 10}, {0, x < 0}, {0, x > 10}}];
g[x_] = f[x];
n = 20;
For[i = 1, i <= n, i++, g[y_] = Convolve[f[x], g[x], x, y]];
Plot[g[x], {x, -10, n*10 + 10}, PlotRange -> All]
Edit: While this works, agentp's answer is more consise and i suspect also faster.
I've got this case statement which is giving an error 'variable constant1 is unused'. It seems to be ignoring the variables and returning the top line, so the variables obviously haven't got scope. If I replace the constant with a number 1 then it works. What is the best way of doing this in Elixir?
defmodule Main
do
def constant1, do: 1
def constant2, do: 1
def constant3, do: 1
x = 1
y = 0
z = 0
{a, b, c, d} =
case {x, y, z} do
{constant1, constant2, constant3} -> {1, 2, 3, 4}
{constant1, constant2, _} -> {5, 6, 7, 8}
{constant1, _, _} -> {9, 10, 11, 12}
{_, _, _} -> {13, 14, 15, 16}
end
IO.inspect {a, b, c, d}
end
Here is the output:
warning: variable constant1 is unused
Untitled 9:15
{1, 2, 3, 4}
Changing the constants to variables also doesn't work.
You have defined constant1 being a function. When you try to use it in pattern matching, Elixir expects the variable to be there and you’ve got an error. One can’t pattern match to functions.
What you’ve wanted is likely:
defmodule Main do
constant1 = 1
constant2 = 1
constant3 = 1
x = 1
y = 0
z = 0
{a, b, c, d} =
case {x, y, z} do
{^constant1, ^constant2, ^constant3} -> {1, 2, 3, 4}
{^constant1, ^constant2, _} -> {5, 6, 7, 8}
{^constant1, _, _} -> {9, 10, 11, 12}
{_, _, _} -> {13, 14, 15, 16}
end
IO.inspect {a, b, c, d}
end
#⇒ { 9, 10, 11, 12 }
Also, please remember that to pattern match to already defined value, one should use the pin operator ^ in front of matcher, otherwise the code
a = 42
case x do
a -> ...
end
will overwrite the value of a, setting it to the value of x (in the scope of case block, outside of case a will remain 42.) With ^, the code below will match if and only x == 42:
a = 42
case x do
^a -> ...
end
Answering the subsequent questions about “how to,” “can I use globals,” etc.
Elixir (as all known functional languages) has no notion of “global,” since everything is immutable from the outside point of view. True constants are being implemented as macros. Macros are compiled during the compilation stage to AST and therefore might be used as constants inside match:
defmodule Constants do
defmacro constant1 do
quote do: 1
end
defmacro constant2 do
quote do: 1
end
defmacro constant3 do
quote do: 1
end
end
defmodule Main do
require Constants
x = 1
y = 0
z = 0
{a, b, c, d} =·
case {x, y, z} do
{Constants.constant1, Constants.constant2, Constants.constant3} -> {1, 2, 3, 4}
{Constants.constant1, Constants.constant2, _} -> {5, 6, 7, 8}
{Constants.constant1, _, _} -> {9, 10, 11, 12}
{_, _, _} -> {13, 14, 15, 16}
end
IO.inspect {a, b, c, d}
end
The above works, because after compilation there is no Constants.constant1 anymore in Main code: there are real values: 1s and the code being run is:
case {x, y, z} do
{1, 1, 1} -> {1, 2, 3, 4}
{1, 1, _} -> {5, 6, 7, 8}
{1, _, _} -> {9, 10, 11, 12}
{_, _, _} -> {13, 14, 15, 16}
end
Hope it helps.
I am attempting to graph the following function and indicate on the plot where the function passes 45 degree slope. I have been able to graph the function itself using the following code:
T = 170 Degree;
f[s_, d_] = Normal[Series[Tan[T - (d*s)], {s, 0, 4}]];
r[h_, d_] = Simplify[Integrate[f[s, d], {s, 0, h}]];
a[h_] = Table[r[h, d], {d, 1, 4, .5}];
Plot[a[h], {h, 0, 4}, PlotRange -> {{0, 4}, {0, -4}}, AspectRatio -> 1]
I need to display the point on each curve where the slope exceeds 45 degrees. However, I have thus far been unable to even solve for the numbers, due to something odd about the hadling of tables in the Solve and Reduce functions. I tried:
Reduce[{a'[h] == Table[-1, {Dimensions[a[h]][[1]]}], h >= 0}, h]
But I apparently can't do this with this kind of function, and I am not sure how to add these results to the plot so that each line gets a mark where it crosses. Does anyone know how to set this up?
Here is your code, for completeness, with plot parameters slightly modified to zoom into the region of interest:
Clear[d,h,T,f,r,a];
T = 170 Degree;
f[s_, d_] = Normal[Series[Tan[T - (d*s)], {s, 0, 4}]];
r[h_, d_] = Simplify[Integrate[f[s, d], {s, 0, h}]];
a[h_] = Table[r[h, d], {d, 1, 4, .5}];
plot = Plot[a[h], {h, 0, 4}, PlotRange -> {{0, 0.8}, {0, -0.5}},
AspectRatio -> 1, Frame -> {False, True, True, False},
FrameStyle -> Directive[FontSize -> 10],
PlotStyle -> {Thickness[0.004]}]
Here is the code to get the solutions (h-coordinates):
In[42]:= solutions = Map[Reduce[{D[#, h] == -1, h >= 0}, h] &, a[h]]
Out[42]= {h == 0.623422, h == 0.415615, h == 0.311711, h == 0.249369,
h == 0.207807, h == 0.178121, h == 0.155856}
Now produce the plot:
points = ListPlot[MapIndexed[{#1, a[#1][[First##2]]} &, solutions[[All, 2]]],
PlotStyle -> Directive[PointSize[0.015], Red],
PlotRange -> {{0, 0.8}, {0, -0.5}}, AspectRatio -> 1,
Frame -> {False, True, True, False},
FrameStyle -> Directive[FontSize -> 10]]
Finally, combine the plots:
Show[{plot, points}]
Edit:
Responding to the request of cutting plots at the found points - here is one way:
plot =
With[{sols = solutions[[All, 2]]},
Plot[Evaluate[a[h]*UnitStep[sols - h]], {h, 0, 4},
PlotRange -> {{0, 0.8}, {0, -0.5}}, AspectRatio -> 1,
Frame -> {False, True, True, False},
FrameStyle -> Directive[FontSize -> 10],
PlotStyle -> {Thickness[0.004]}]]
and this should be executed after the solutions have been found.
Could find the points via:
slope45s =
h /. Map[First[Solve[D[#, h] == -1 && h >= 0, h]] &, a[h]]
Out[12]= {0.623422, 0.415615, 0.311711, 0.249369, 0.207807, 0.178121, \
0.155856}
Here we put together the list of relevant points.
pts = Transpose[{slope45s, Tr[a[slope45s], List]}]
Can now plot in any number of ways. Here is one such.
p2 = ListPlot[pts, PlotRange -> {{0, 4}, {0, -4}},
PlotStyle -> {PointSize[.01], Red}];
p1 = Plot[a[h], {h, 0, 4}, PlotRange -> {{0, 4}, {0, -4}},
AspectRatio -> 1];
Show[p1, p2]
(Being new to this modern world-- or rather, of an age associated with an earlier civilization-- I do not know how to paste in an image.)
(Okay, thanks Leonid. I think I have an image and also indented code.)
(But why are we talking in parentheses??)
Daniel Lichtblau
Wolfram Research
Edit: I did not much like the picture I gave. Here is one I think is more descriptive.
makeSegment[pt_, slope_, len_] :=
Rotate[Line[{pt + {-len/2, 0}, pt + {len/2, 0}}], ArcTan[slope]]
p2 = ListPlot[pts, PlotStyle -> {PointSize[.01], Red}];
p1 = Plot[a[h], {h, 0, 4}, PlotRange -> {{0, 2}, {0, -1}},
AspectRatio -> 1];
p3 = Graphics[Map[{Orange, makeSegment[#, -1, .2]} &, pts]];
Show[p1, p2, p3, AspectRatio -> 1/2, ImageSize -> 1000]