I’d go for roughly the following as an avg function:
def avg(list)
list
|> Enum.reduce({0, 0}, &avg/2)
|> avg_finalize
end
defp avg(x, {sum, count}), do: {sum + x, count + 1}
defp avg_finalize({sum, count}), do: sum / count
The cool thing about this is, that you only need to iterate a single time over the input list.
Currently it would fail on non-numeric input, but you can easily define appropriate guards. Adding one which does simply ignore nils should be easy.
And as a small rule of thumb, when you start chaining from one Enum-function into another, you might think about using Stream instead to reduce the number of iterations over the complete input.
But this really depends on the size of your input, if your input is short enough and the Enum-chains also, then Stream might take much more time.
You say “loop” and that makes me wonder. I don’t see a good way to do it in one pass with a list comprehension. I can do it with recursion, but I prefer Enum.reduce
defmodule Test do
def avg(maps), do: avg(maps, {0,0})
def avg([], {total, count}) when count > 0, do: total / count
def avg([%{height: height} | tail], {total, count}), do: avg(tail, {total + height, count + 1})
def avg([_ | tail], acc), do: avg(tail, acc)
end
people = [%{name: 'Mary', height: 160},
%{name: 'Paul', height: 180},
%{name: 'Hugo'}]
IO.puts Test.avg(people)
So getting just a list of maps containing all of the dockerNumber’s and playedBy’s only would be as a direct translation of your next javascript (assuming you meant to swap the keys and values since they were backwards):
for
%{doctorNumber: doctorNumber, playedBy: playedBy} <- doctors, # First grab each doctor out of the list (you can also match out parts here too, but it is numerous in this example so keeping it short)
doctor.begin > 2000, # Then filter on a condition
do: %{ # Then return the result after filtering, this example can be arbitrarily complex and remains easier to read when it does
doctorNumber: "#" <> to_string(doctor.number),
playedBy: doctor.actor,
yearsPlayed: doctor.end - doctor.begin + 1
}
Or something like that.
EDIT: Also, this forum is Discourse, it supports normal markdown, so using code fences like:
```elixir
def Some elixir code
```
```javascript
var Some javascript code
```
Hi ,
I have a query, I would like to make dynamic Sql statements for multiple where clauses in elixir and pass it across to raw queries.
Please note i use sql.format in my nodejs code to prevent “SQL injection”
my existing javascript code looks likes this
var interns = [{
"name": "donnie"
}, {
"age": 16
}, {
"gender": "male"
}]
var selector = ""
interns.forEach(function(item, index) {
var searchvalue = item[Object.keys(item)];
var searchkey = Object.keys(item)[0];
if (selector == "") {
selector = "and " + (searchkey) + " LIKE " + "'%" + (searchvalue) + "%'";
} else {
selector = selector + " and " + (searchkey) + " LIKE " + "'%" + (searchvalue) + "%'";
}
})
console.log(selector)
, how can we achieve the same in elixir .
my progress is kinda stuck in how to trigger else clause and append to z variable
user_params=[%{"age" => 19}, %{"name" => "matt213"}, %{"sex" => "male"}]
sqlwhere=1;
z="";
for norm <- user_params do
for {k, x} <- norm do
IO.inspect sqlwhere
if sqlwhere <=1 do
intern=" and #{k} = '#{x}'"
x = "and #{k}="
y = "'#{x}'"
z = x <> " " <> y
IO.inspect z
sqlwhere=sqlwhere+1;
else
IO.inspect "unable to get here !"
# j = "#{k}"
# l = "#{x}"
# k = j <> " " <> l
# IO.inspect k
#list=list+"#{list} where #{k} = '#{x}'"
end
end
end
Using strings for building SQL is risky. Fortunately with ecto, we don’t have to do it:
user_params = [%{"age" => 19}, %{"name" => "matt213"}, %{"sex" => "male"}]
user_params
|> Enum.map(&Enum.to_list/1)
|> Enum.reduce(Foo, fn [{key, value}], query ->
field = String.to_existing_atom(key)
search = "%#{value}%"
from q in query, where: like(field(q, ^field), ^search)
end
where Foo is the schema you want to search. I would also probably employ some more advanced mechanism for filtering allowed fields than String.to_existing_atom/1, but for an example it’s good enough.
You don’t want to do Repo.all inside the Enum.reduce callback. The idea is that reduce is reducing over a single query, building it up with each iteration. The return value of the Enum.reduce is the query that you want to execute.
Affirmative , now it seems quite clear the functional usage of repo, thanks !
one more query what modification is required in code if the incoming user_params look like this
hi ,
below is my modified codebase , it throws below error
** (exit) an exception was raised:
** (Protocol.UndefinedError) protocol Ecto.Queryable not implemented for
[ecto.Query from u in HelloPhoenix.User, where: like(u.age, ^“%19%”)>, ecto.Query
from u in HelloPhoenix.User, where: like(u.name, ^“%matt213%”)>]
Modified Codebase
query=user_params
|> Enum.map(&Enum.to_list/1)
|> Enum.reduce(User, fn thing, query ->
for {key, value} <- thing do
field = String.to_existing_atom(key)
search = "%#{value}%"
from q in query, where: like(field(q, ^field), ^search)
end
end)
user = Repo.all(query)
IO.inspect user