small medium large xlarge

• (Harder) Write a function that takes a single-quoted string of the form number [+-*/] number and returns the result of the calculation. The individual numbers do not have leading plus or minus signs.

`calculate('123 + 27') # => 150`

A Possible Solution</summary>

```defmodule Parse do

def calculate(expression) do
{ n1, rest } = parse_number(expression)
rest         = skip_spaces(rest)
{ op, rest } = parse_operator(rest)
rest         = skip_spaces(rest)
{ n2, [] }   = parse_number(rest)
op.(n1, n2)
end

defp parse_number(expression), do: _parse_number({ 0, expression })

defp _parse_number({value, [ digit | rest ] }) when digit in ?0..?9 do
_parse_number({ value*10 + digit - ?0, rest})
end

defp _parse_number(result), do: result

defp skip_spaces([ ?  | rest ]), do: skip_spaces(rest)
defp skip_spaces(rest),          do: rest

defp parse_operator([ ?+ | rest ]), do: { &1+&2, rest }
defp parse_operator([ ?- | rest ]), do: { &1-&2, rest }
defp parse_operator([ ?* | rest ]), do: { &1*&2, rest }
defp parse_operator([ ?/ | rest ]), do: { div(&1, &2), rest }

end

IO.inspect Parse.calculate('23+45')     #=> 68
IO.inspect Parse.calculate('34  - 56')  #=> -22
IO.inspect Parse.calculate('12 * 23')   #=> 276
IO.inspect Parse.calculate('123 / 8')   #=> 15

```

</details>

I ended up browsing elixir library to find how to trim spaces in a string and convert string to a number. I have following implementation.

I have regular expression twice in the function. How can I compile it so that I can reuse expression?

``````defmodule MyString do

def eval(expression) do
list = Regex.split(%r/\*|\+|\/|-/,expression)
op = Regex.run(%r/\*|\+|\/|-/,expression)
[n1,n2] = list
_eval([_to_int(n1),_to_int(n2)], List.flatten(op))
end

defp _to_int(n), do: binary_to_integer(String.strip(String.from_char_list!(n)))

defp _eval([n1, n2], '+'), do: n1 + n2
defp _eval([n1, n2], '-'), do: n1 - n2
defp _eval([n1, n2], '/'), do: div(n1, n2)
defp _eval([n1, n2], '*'), do: n1 * n2

end
``````

Here is mine. It basically uses `Enum.chunk_by/2` to extract the operands and the operator, and then uses pattern matching to do the correct calculation.

``````defmodule Calculator do
def calculate(operation) do
{ operand1, operator, operand2 } = extract_parts(operation)
calculate(operator, operand1, operand2)
end

defp calculate('+', operand1, operand2), do: operand1 + operand2
defp calculate('-', operand1, operand2), do: operand1 - operand2
defp calculate('*', operand1, operand2), do: operand1 * operand2
defp calculate('/', operand1, operand2), do: div(operand1, operand2)

defp extract_parts(operation) do
space?    = &( &1 == (? ) )
operator? = &( &1 in '+-/*' )
[operand1, operator, operand2] = operation |> Enum.reject(space?)
|> Enum.chunks_by(operator?)
{ chars_to_integer(operand1), operator, chars_to_integer(operand2) }
end

defp chars_to_integer(characters) do
characters |> to_string |> binary_to_integer
end
end
``````
``````
def calculate(expression) do
{ left, rest } = Enum.split_while(expression, &(!(&1 in '+-*/')))
[ op | right ] = rest
{ result, _ } = Code.eval_quoted { list_to_atom([op]), [],
[value(left), value(right)] }
result
end

padded_digits |> to_string |> String.strip |> binary_to_integer

``````

Since this chapter was shortly have list recursion I decided to try using Enum.reduce for extracting. Not really happy with how verbose _extract_helper ended up though…

``````	def calculate(string_list) do
{num1, op, num2} = _extract_components(string_list)
case op do
?+ -> number(num1) + number(num2)
?/ -> number(num1) / number(num2)
?* -> number(num1) * number(num2)
?- -> number(num1) - number(num2)
end
end

defp _extract_components(string_list) do
Enum.reduce(string_list, {nil, nil, nil}, fn(elem, acc) -> _extract_helper(elem, acc) end)
end

# Ignore spaces
defp _extract_helper(? , acc), do: acc

defp _extract_helper(elem, {nil, nil, _num2})
when elem in '01234566789' do
{[elem], nil, nil}
end

defp _extract_helper(elem, {num1, nil, _num2})
when elem in '01234566789' do
{num1 ++ [elem], nil, nil}
end

defp _extract_helper(elem, {num1, nil, _num2})
when elem in '/+-*' do
{num1, elem, nil}
end

defp _extract_helper(elem, {num1, op, nil})
when elem in '01234566789' do
{num1, op, [elem]}
end

defp _extract_helper(elem, {num1, op, num2})
when elem in '01234566789' do
{num1, op, num2 ++ [elem]}
end

defp number(characters) do
characters |> to_string |> binary_to_integer
end
``````

This would have been four lines shorter if I had found a way to dynamically reference Kernel.+/2 and friends.

``````  def calculate(str) do
{x, op, y} = _parse(str, {0, :op, 0})
op.(x, y)
end

defp _parse([]     , acc      )                 , do: acc
defp _parse([h | t], {a, b, c}) when h in ?0..?9, do: _parse(t, {a, b, c * 10 + h - ?0})
defp _parse([h | t], {_, _, c}) when h in '+-*/', do: _parse(t, {c, _fn(h), 0})
defp _parse([_ | t], acc      )                 , do: _parse(t, acc)

defp _fn(?+), do: &Kernel.+/2
defp _fn(?-), do: &Kernel.-/2
defp _fn(?*), do: &Kernel.*/2
# defp _fn(?/), do: &Kernel.//2   # Nope, guess again
defp _fn(?/), do: &div/2        # or &(&1 / &2) or ("#{div &1, &2} remainder #{rem &1, &2}")
``````

Thanks to José Valim answering my question on StackOverflow, here’s a version that calls the operator dynamically:

``````  def calculate(str) do
{x, op, y} = _parse(str, {0, :op, 0})
apply :erlang, list_to_atom(op), [x, y]
end

defp _parse([]     , acc      )                 , do: acc
defp _parse([h | t], {a, b, c}) when h in ?0..?9, do: _parse(t, {a, b, c * 10 + h - ?0})
defp _parse([h | t], {_, _, c}) when h in '+-*/', do: _parse(t, {c, [h], 0})
defp _parse([_ | t], acc      )                 , do: _parse(t, acc)
``````
``````defmodule Parse do
def calculate(str), do: _calculate(str, 0)

defp _calculate([], value), do: value
defp _calculate([?  | tail], value), do: _calculate(tail, value)
defp _calculate([digit | tail], value) when digit in '0123456789', do: _calculate(tail, value * 10 + digit - ?0)
defp _calculate([operator | tail], value) when operator in '+-*/', do: apply(:erlang, list_to_atom([operator]), [value, calculate(tail)])
end

IO.inspect Parse.calculate('23+45')     #=> 68
IO.inspect Parse.calculate('34  - 56')  #=> -22
IO.inspect Parse.calculate('12 * 23')   #=> 276
IO.inspect Parse.calculate('123 / 8')   #=> 15.375

# Also:
IO.inspect Parse.calculate('123 + 40 / 8')   #=> 128.0
IO.inspect Parse.calculate('123 * 10 / 2')   #=> 615.0
``````

I have to admit I lost my patience on this one and just cheated :)

``````defmodule Calc do
def eval(expression) do
{result, _} = Code.eval_string(expression)
result
end
end
``````

Dave’s original solution no longer works with recent versions of Elixir. You’ll get the following output:

``````pi@elixirpi ~/learn_elixir \$ elixir parse.exs
parse.exs:19: warning: found ? followed by codepoint 0x20 (space), please use \s instead
** (CompileError) parse.exs:22: unhandled &1 outside of a capture
(stdlib) lists.erl:1352: :lists.mapfoldl/3
(stdlib) lists.erl:1352: :lists.mapfoldl/3
(elixir) src/elixir_clauses.erl:36: :elixir_clauses.clause/7
``````

``````defmodule Parse do

def calculate(expression) do
{ n1, rest } = parse_number(expression)
rest         = skip_spaces(rest)
{ op, rest } = parse_operator(rest)
rest         = skip_spaces(rest)
{ n2, [] }   = parse_number(rest)
op.(n1, n2)
end

defp parse_number(expression), do: _parse_number({ 0, expression })

defp _parse_number({value, [ digit | rest ] }) when digit in ?0..?9 do
_parse_number({ value*10 + digit - ?0, rest})
end

defp _parse_number(result), do: result

defp skip_spaces([ ?\s | rest ]), do: skip_spaces(rest)
defp skip_spaces(rest),           do: rest

defp parse_operator([ ?+ | rest ]), do: { &(&1+&2), rest }
defp parse_operator([ ?- | rest ]), do: { &(&1-&2), rest }
defp parse_operator([ ?* | rest ]), do: { &(&1*&2), rest }
defp parse_operator([ ?/ | rest ]), do: { &(div(&1, &2)), rest }

end

IO.inspect Parse.calculate('23+45')     #=> 68
IO.inspect Parse.calculate('34  - 56')  #=> -22
IO.inspect Parse.calculate('12 * 23')   #=> 276
IO.inspect Parse.calculate('123 / 8')   #=> 15
``````

This is my solution. Turned out to be much simpler than initially what I thought.

``````
defmodule Parse do
defp _calculate([], num1, ?+, num2) do: num1 + num2
defp _calculate([], num1, ?-, num2) do: num1 - num2
defp _calculate([], num1, ?*, num2) do: num1 * num2
defp _calculate([], num1, ?/, num2) do: num1 / num2
defp _calculate([head | tail], num1, ?=, 0) when head == 32, do: _calculate(tail, num1, ?=, 0)
defp _calculate([head | tail], num1, ?=, 0) when head in [?+, ?-, ?*, ?/], do: _calculate(tail, num1, head, 0)
defp _calculate([head | tail], num1, ?=, 0), do: _calculate(tail, (num1*10)+(head-?0), ?=, 0)
defp _calculate([head | tail], num1, op, 0) when head == 32, do: _calculate(tail, num1, op, 0)
defp _calculate([head | tail], num1, op, num2), do: _calculate(tail, num1, op, (num2*10)+(head-?0))

def calculate(string) do
_calculate(string, 0, ?=, 0)
end
end

iex(90)> Parse.calculate('123000 + 27')
123027
iex(91)> Parse.calculate('123000+27')
123027
iex(92)> Parse.calculate('123000 +27')
123027
iex(93)> Parse.calculate('123000+ 27')

``````

Conveniently with strings:

``````defmodule Comp do

def calc(charl) do
[op1, op, op2] = to_string(charl) |> String.split
ops = [op1, op2] |> Enum.map(&String.to_integer/1)
fun = fn
"+", [op1, op2] -> op1 + op2
"-", [op1, op2] -> op1 - op2
"*", [op1, op2] -> op1 * op2
"/", [op1, op2] -> op1 / op2
end
fun.(op, ops)
end
end
``````

I tried to solve this without using built in functions, I reused Dave’s example in the book for converting digit to integer.

```defmodule MyString do

def calculate(str) do
{left, op, right} = _parse(str, '')
_calculate(_number_digits(left, 0), _number_digits(right, 0), op)
end

defp _calculate(left, right, op) when op == ?+, do: left + right
defp _calculate(left, right, op) when op == ?-, do: left - right
defp _calculate(left, right, op) when op == ?*, do: left * right
defp _calculate(left, right, op) when op == ?/, do: left / right

defp _parse([], value), do: { value, '', ' ' }
end
defp _parse([head | tail], value) do
end

defp _number_digits([], value), do: value
defp _number_digits([ digit | tail ], value)
when digit in '0123456789' do
_number_digits(tail, value * 10 + digit - ?0)
end
defp _number_digits([ digit | tail ], value)
when digit in ' _' do
_number_digits(tail, value)
end

end
```

My solution is like T. Kort’s but a little shorter. With the problem it won’t work if the numbers are not separated by spaces.

```defmodule MyString
def parse(xs) do
[num1, operator, num2] = to_string(xs) |> String.split

apply Kernel, String.to_atom(operator), Enum.map([num1, num2], &String.to_integer/1)
end
end
```
``````defmodule Strings do
def calculate(exp), do: _calculate(exp, 0)
defp _calculate([], value), do: value
defp _calculate([? | t], value), do: _calculate(t, value)
defp _calculate([?+ | t], value), do: value + _calculate(t, 0)
defp _calculate([?- | t], value), do: value - _calculate(t, 0)
defp _calculate([?* | t], value), do: value * _calculate(t, 0)
defp _calculate([?/ | t], value), do: value / _calculate(t, 0)
defp _calculate([digit | t], value) when digit in '0123456789' do
_calculate(t, value*10 + digit - ?0)
end
end
``````

There is, however, this error:

warning: found ? followed by codepoint 0x20 (space), please use \s instead

Here’s my solution. Could have used the parse methods from the previous example to convert to numbers, but left them out for brevity as I was more interested in how to parse the body of the expression.

``````defmodule Parse do

def calculate(expression) do
do_calculate(expression, '', '', '')
end

defp do_calculate([op|t], left, _, _) when op in '+-*/' do
do_calculate(t, left, List.to_atom([op]), '')
end

defp do_calculate([h|t], left, op, right) when h === ?\s do
do_calculate(t, left, op, right)
end

defp do_calculate([h|t], left, '', '') do
do_calculate(t, [h|left], '', '')
end

defp do_calculate([h|t], left, op, right) do
do_calculate(t, left, op, [h|right])
end

defp do_calculate([], left, op, right) do
x = left  |> Enum.reverse |> List.to_integer
y = right |> Enum.reverse |> List.to_integer
apply :erlang, op, [x, y]
end
end
``````

I cheated using &List.to_string/1, but here is a solution working with both single and double quoted strings.

``````defmodule Parse do
def calculate(formula) when is_list(formula), do: _calculate(List.to_string(formula))
def calculate(formula), do: _calculate(formula)

defp _calculate([number1, "+", number2]), do: number1 + number2
defp _calculate([number1, "-", number2]), do: number1 - number2
defp _calculate([number1, "*", number2]), do: number1 * number2
defp _calculate([number1, "/", number2]), do: number1 / number2

defp _calculate(formula)
do
operation = Regex.run(~r/(\d+) ?(\+|-|\*|\/) ?(\d+)/, formula)
if not is_nil(operation)
do
operation
|> List.delete_at(0)
|> List.update_at(0, &String.to_integer/1)
|> List.update_at(2, &String.to_integer/1)
|> _calculate
end
end
end
``````

Using Regex.scan

``````defmodule Printables do
@reg ~r{[0-9]+|[\-\+\*\/]}
def calculate(exp) do
Regex.scan(@reg, List.to_string(exp))
|> List.flatten
|> do_calculate
end
defp do_calculate([first, op, second]) do
{f, _} = Integer.parse(first)
{s, _} = Integer.parse(second)
case op do
"+" -> f + s
"-" -> f - s
"*" -> f * s
"/" -> f / s
end
end
defp do_calculate(_), do: raise "Wrong input string format"
end
``````

My simple solution:

```defmodule Exercise do
def pow(x, 0), do: 1
def pow(x, n), do: x * pow(x, n - 1)
def _char_arr2_num([], acc), do: acc
def _char_arr2_num([head | tail], acc) do
_char_arr2_num(tail, acc + (head - hd('0')) * pow(10, Enum.count(tail)))
end
def char_arr2_num(chars), do: _char_arr2_num(chars, 0)
def _parse([],            acc), do: char_arr2_num(acc)
def _parse([?+   | tail], acc), do: char_arr2_num(acc) + _parse(tail, '')
def _parse([?-   | tail], acc), do: char_arr2_num(acc) - _parse(tail, '')
def _parse([?*   | tail], acc), do: char_arr2_num(acc) * _parse(tail, '')
def _parse([?/   | tail], acc), do: char_arr2_num(acc) / _parse(tail, '')
def _parse([?\s  | tail], acc), do: _parse(tail, acc)
def calculate(expr), do: _parse(expr, '')
end
```

Mine was pretty similar to Dave’s but I never thought to limit it to one expression, and decided to parse decimal points.

``````
defmodule Calc do
def calc(str) do
{left, operations} = _pop_operand(str)
operations = _skip_spaces(operations)
_accumulate(left, operations)
end

defp _accumulate(value, []) do
value
end

defp _accumulate(left, expression) do
{ operator, rest } = _pop_operator(expression)
rest = _skip_spaces(rest)
{ right, rest } = _pop_operand(rest)
rest = _skip_spaces(rest)
_accumulate(operator.(left, right), rest)
end

defp _skip_spaces( [ ?\s | str]), do: _skip_spaces(str)
defp _skip_spaces(str), do: str

defp _pop_operand(str), do: _pop_operand(str, 0)
defp _pop_operand([], value), do: {value, []}
defp _pop_operand([ digit | tail ], value)
when digit in ?0..?9 do
_pop_operand(tail, value*10 + (digit - ?0))
end
defp _pop_operand([ ?. | tail ], value) do
_pop_mantissa(tail, value, 1)
end
defp _pop_operand(rest, value), do: {value, rest}
defp _pop_mantissa([ digit | tail ], value, digits)
when digit in ?0..?9 do
_pop_mantissa(tail, value + ((digit - ?0) / :math.pow(10, digits)), digits+1)
end
defp _pop_mantissa(rest, value, _), do: {value, rest}

defp _pop_operator([ ?+ | tail ]), do: { &(&1 + &2), tail}
defp _pop_operator([ ?- | tail ]), do: { &(&1 - &2), tail}
defp _pop_operator([ ?* | tail ]), do: { &(&1 * &2), tail}
defp _pop_operator([ ?/ | tail ]), do: { &(&1 / &2), tail}
defp _pop_operator(non_operator) do
raise "Invalid operator '#{[non_operator]}'"
end
end

``````

Here is mine:

``````defmodule Strings do
def calculate(calculation) do
_calculate(calculation, 0)
end

defp _calculate([], value), do: value
defp _calculate([ ?+ | tail ], value), do: value + _calculate(tail, 0)
defp _calculate([ ?- | tail ], value), do: value - _calculate(tail, 0)
defp _calculate([ ?* | tail ], value), do: value * _calculate(tail, 0)
defp _calculate([ ?/ | tail ], value), do: value / _calculate(tail, 0)
defp _calculate([ ?\s | tail ], value), do: _calculate(tail, value)
defp _calculate([ head | tail ], value) do
_calculate(tail, value * 10 + digit)
end
end
``````

My solution (not sure on the efficiency, but I think it reads well…also is very particular to the format of the parameter, but I think that’s acceptable based on the question):

``````def calculate(str) do
chunked = Enum.chunk_by(Enum.filter(str, &(&1 != 32)), &(&1 in '+-/*'))
_calculate chunked
end
defp _calculate([ a, '+', b ]), do: List.to_integer(a) + List.to_integer(b)
defp _calculate([ a, '-', b ]), do: List.to_integer(a) - List.to_integer(b)
defp _calculate([ a, '*', b ]), do: List.to_integer(a) * List.to_integer(b)
defp _calculate([ a, '/', b ]), do: List.to_integer(a) / List.to_integer(b)
``````

My solution expects exactly 1 space between numbers and operater as that is how I read the contract of the char_list to be in the exercise.

```defmodule StringMath do

def calculate(lst) do
[num1, ' ', action, ' ', num2] = Enum.chunk_by(lst, &(&1 == ?\s))
_calculate(_get_integer(num1), action, _get_integer(num2))
end

defp _calculate(num1, '+', num2), do: num1 + num2
defp _calculate(num1, '-', num2), do: num1 - num2
defp _calculate(num1, '*', num2), do: num1 * num2
defp _calculate(num1, '/', num2), do: div(num1, num2)

defp _get_integer(number) do
{int, []} = :string.to_integer(number)

int
end
end
```

My simple solution does not use library functions when parsing and accepts flexible input strings.

```````def` calculate(expr) when is_list(expr)  do
unless to_string(expr) =~ ~r/^\s*\d+\s*[\+\-\*\/]\s*\d+\s*\$/ do
false
else
{operator, first_operand, second_operand} = parse(expr, {})
do_calculate operator, first_operand, second_operand
end
end

defp parse([], {o, f, s}), do: {o, f, s}
defp parse([h | t], res) when h == ?\s, do: parse(t, res)
defp parse([h | t], {}) when h in ?0..?9, do: parse(t, {nil, h - ?0, 0})
defp parse([h | t], {nil, f, s}) when h in ?0..?9, do: parse(t, {nil, f * 10 + (h - ?0), s})
defp parse([h | t], {nil, f, s}) when h in [?+, ?-, ?*, ?/], do: parse(t, {h, f, s})
defp parse([h | t], {o, f, s}) when h in ?0..?9, do: parse(t, {o, f, s * 10 + (h - ?0)})

defp do_calculate(operator, first_operand, second_operand) when operator == ?+, do: first_operand + second_operand
defp do_calculate(operator, first_operand, second_operand) when operator == ?-, do: first_operand - second_operand
defp do_calculate(operator, first_operand, second_operand) when operator == ?*, do: first_operand * second_operand
defp do_calculate(operator, first_operand, second_operand) when operator == ?/, do: first_operand / second_operand

``````

Here is my solution (highly inspired by strings/parse.exs example)

``````defmodule Calculator do
def calculate(str), do: _calculate(str, 0, 0, nil)
defp _calculate(number1, number2, ?+) do
number1 + number2
end
defp _calculate(number1, number2, ?-) do
number1 - number2
end
defp _calculate(number1, number2, ?*) do
number1 * number2
end
defp _calculate(number1, number2, ?/) do
number1 / number2
end
defp _calculate([?\s|tail], number1, number2, op) do
_calculate(tail, number1, number2, op)
end
defp _calculate([digit|tail], number1, number2, nil)
when digit in '0123456789' do
_calculate(tail, number1*10 + digit - ?0, number2, nil)
end
defp _calculate([digit|tail], number1, number2, op)
when digit in '0123456789' do
_calculate(tail, number1, number2*10 + digit - ?0, op)
end
end
defp _calculate([_|_], _, _, _) do
raise "Invalid char"
end
defp _calculate([], number1, number2, op) do
_calculate(number1, number2, op)
end
end

IO.puts Calculator.calculate('  10 + 20')
``````

Just using concepts learned thus far. Accounts for spaces as well, but expects valid syntax and does not account for division by zero

``````
def calc(l) do
_calc(l, 0)
end

def _calc([h | t], total) when h == ?\s do
_calc(t, total)
end

def _calc([h | t], total) when h == ?+ do
total + _calc(t, 0)
end

def _calc([h | t], total) when h == ?- do
total - _calc(t, 0)
end

def _calc([h | t], total) when h == ?* do
total * _calc(t, 0)
end

def _calc([h | t], total) when h == ?/ do
total / _calc(t, 0)
end

def _calc([h | t], total) do
_calc(t, total * 10 + h - ?0)
end

def _calc([], total) do
total
end

``````

my solution is one of the longest, but gets the job done anyway. The solutions from Artem Medeyshev and T.Kort are the best and I like a succinctness of these solutions:

``````defmodule Calculate do

def calculate(list) do

sign = list |> Enum.filter(fn(x) -> x == ?+ or x == ?-
or x == ?* or x == ?/ end)

case '#{sign}' do
'+' ->
value1 = list
|> Enum.filter(fn(x) -> x != ?\s end)
|> Enum.take_while(fn(x) -> x != ?+ end)
|> List.to_integer
value2 = list
|> Enum.reverse
|> Enum.filter(fn(x) -> x != ?\s end)
|> Enum.take_while(fn(x) -> x != ?+ end)
|> Enum.reverse |> List.to_integer
IO.puts("calculate('#{value1} #{sign} #{value2}') # => #{value1+value2}")
'-' ->
value1 = list
|> Enum.filter(fn(x) -> x != ?\s end)
|> Enum.take_while(fn(x) -> x != ?- end)
|> List.to_integer
value2 = list
|> Enum.reverse
|> Enum.filter(fn(x) -> x != ?\s end)
|> Enum.take_while(fn(x) -> x != ?- end)
|> Enum.reverse |> List.to_integer
IO.puts("calculate('#{value1} #{sign} #{value2}') # => #{value1-value2}")
'*' ->
value1 = list
|> Enum.filter(fn(x) -> x != ?\s end)
|> Enum.take_while(fn(x) -> x != ?* end)
|> List.to_integer
value2 = list
|> Enum.reverse
|> Enum.filter(fn(x) -> x != ?\s end)
|> Enum.take_while(fn(x) -> x != ?* end)
|> Enum.reverse |> List.to_integer
IO.puts("calculate('#{value1} #{sign} #{value2}') # => #{value1*value2}")
'/' ->
value1 = list
|> Enum.filter(fn(x) -> x != ?\s end)
|> Enum.take_while(fn(x) -> x != ?/ end)
|> List.to_integer
value2 = list
|> Enum.reverse
|> Enum.filter(fn(x) -> x != ?\s end)
|> Enum.take_while(fn(x) -> x != ?/ end)
|> Enum.reverse |> List.to_integer
IO.puts("calculate('#{value1} #{sign} #{value2}') # => #{value1/value2}")
end
end
end
``````

My first blind attempt. I wanted to try using some of the various functions I haven’t used yet. It works but looks a bit clunky. It can handle bizarre input such as ‘1adAd2*aaDad D a 1 2’ as long as it filters out to left and right hand operands and a single operator.

``````defmodule Calculate do
def calculate(exp) do
exp #'100 + 45'
|> Enum.filter(&(&1 >= ?0 && &1 <= ?9 || &1 == ?+ || &1 == ?- || &1 == ?* || &1 == ?/)) #'100+45'
|> Enum.chunk(1, 1) #['1','0','0','+','4','5']
|> Enum.chunk_by(&(&1in ['+','-','*','/'])) #[['1','0','0'],['+'],['4','5']]
|> _calculate
end

defp _calculate([left, op, right]) do
l = :erlang.list_to_integer(List.flatten(left))
r = :erlang.list_to_integer(List.flatten(right))
case op do
['+'] -> l + r
['-'] -> l - r
['*'] -> l * r
['/'] -> if r > 0 do l / r else raise "Division by zero." end
end
end

defp _calculate(_), do: raise "Invalid input format."
end
``````

I understood this problem differently and thought the goal was to support any number of calculations in the same list (e.g. ‘123 + 321 * 2 - 5’)
With that in mind, this is my solution (which solves the asked problem too since it’s a special case of my solution, but I failed to realise it could’ve been simpler)

```defmodule Calculator do

def calculate(str) do
# removing spaces this way simplifies the structure of the code
str |> Enum.reject(&(&1 == ?\s)) |> _parse([], 0) |> _compute
end

defp _compute([]), do: 0
defp _compute([value]), do: value
defp _compute([n1, op, n2 | tail]), do: _compute([op.(n1, n2) | tail])

defp _parse([], stack, value), do: stack ++ [value]
defp _parse([digit | tail], stack, value) when digit in '0123456789' do
_parse(tail, stack, value * 10 + (digit - ?0))
end
defp _parse([op | tail], stack, value) when op in '+-*/' do
op_func = case op do
?+ -> &+/2
?- -> &-/2
?* -> &*/2
?/ -> &//2
end
_parse(tail, stack ++ [value, op_func], 0)
end
defp _parse([invalid|_], _, _) do
raise "Invalid character #{invalid}"
end

end
```

I separated the parsing from the computation because they are two different operations, conceptually.
I also used a case to avoid repeating the recursive call on different pattern matches.

I’ve cheated with regex :)

``````def calculate(list_string) do
string = list_string |> List.to_string
reg    = ~r/(?<a>\d+)\s{0,}(?<operator>[-+\/\*]{1})\s{0,}(?<b>\d+)/
data   = Regex.named_captures(reg, string)

%{"a" => a, "b" => b, "operator" => operator} = data
a = a |> String.to_integer
b = b |> String.to_integer

case operator do
"+" -> a + b
"-" -> a - b
"*" -> a * b
"/" -> a / b
end
end
``````

Regex and result pattern matching:

``````def calculate(expression) do
case Regex.named_captures(~r/(?<first>[123456789]\d*)\s*(?<operand>[\+-\\*\/])\s*0*(?<second>[123456789]\d*)/, expression) do
%{"first" => a, "operand" => "+", "second" => b} ->
elem(Integer.parse(a),0) + elem(Integer.parse(b),0)
%{"first" => a, "operand" => "-", "second" => b} ->
elem(Integer.parse(a),0) - elem(Integer.parse(b),0)
%{"first" => a, "operand" => "*", "second" => b} ->
elem(Integer.parse(a),0) * elem(Integer.parse(b),0)
%{"first" => a, "operand" => "/", "second" => b} ->
elem(Integer.parse(a),0) / elem(Integer.parse(b),0)
%{"first" => _, "operand" => non_support, "second" => _} ->
raise "Not supported operand '#{non_support}'"
_ -> raise "Not parsable input"
end
end
``````

I had a very natural approach:

• a function to find each term
• a function to find the operator
• a function that does the calculation

I believe this ended-up in an easy to understand module. I chose to use the functions we’ve seen so far in the book:

```defmodule StringsAndBinaries.Exercise4 do
def calculate(expression) do
_calculate(term(expression, :left), term(expression, :right), operator(expression))
end

defp term(expression, position_sym) do
terms = Enum.chunk_by(expression, &(&1 in '?\s+-*/'))
position = case position_sym do
:left -> 0
_ -> -1
end

terms
|> Enum.at(position)
|> List.to_integer
end

defp operator(expression) do
Enum.partition(expression, fn(x) -> x in '+-*/' end)
|> Tuple.to_list
|> Enum.at(0)
end

defp _calculate(term1, term2, operator) do
case operator do
'+' -> term1 + term2
'-' -> term1 - term2
'*' -> term1 * term2
'/' -> term1 / term2
end
end
end

128 = StringsAndBinaries.Exercise4.calculate('32+96')
128 = StringsAndBinaries.Exercise4.calculate('32 + 96')
128 = StringsAndBinaries.Exercise4.calculate('256-128')
128 = StringsAndBinaries.Exercise4.calculate('256 - 128')
128 = StringsAndBinaries.Exercise4.calculate('32*4')
128 = StringsAndBinaries.Exercise4.calculate('32 * 4')
128.0 = StringsAndBinaries.Exercise4.calculate('512/4')
128.0 = StringsAndBinaries.Exercise4.calculate('512 / 4')
```
``````defmodule Parse do

def calculate(l) do
[root] = l
|> _tokenize
|> _parse_multiplication([])
|> Enum.reverse
_calculate(root)
end

defp _tokenize([]),  do: []
defp _tokenize([?\s | rest]), do: _tokenize(rest)
defp _tokenize([?+ | rest]), do: [:add | _tokenize(rest)]
defp _tokenize([?- | rest]), do: [:subtract | _tokenize(rest)]
defp _tokenize([?* | rest]), do: [:multiply | _tokenize(rest)]
defp _tokenize([?/ | rest]), do: [:divide | _tokenize(rest)]
defp _tokenize([digit | rest])
when digit in '123456789' do _number_token(rest, digit - ?0) end

defp _number_token([digit | tail], number)
when digit in '0123456789' do _number_token(tail, number * 10 + digit - ?0) end
defp _number_token(rest, number), do: [{:number, number} | _tokenize(rest)]

defp _parse_multiplication([], col), do: col
defp _parse_multiplication([left, binary_op, right | rest], col)
when binary_op in ~w(multiply divide)a do
_parse_multiplication(rest, [{binary_op, left, right} | col])
end
defp _parse_multiplication([right | rest], col), do: _parse_multiplication(rest, [right | col])

defp _parse_addition([left, binary_op, right | rest], col)
when binary_op in ~w(add subtract)a do
_parse_addition(rest, [{binary_op, left, right} | col])
end

defp _calculate({:number, num}), do: num
defp _calculate({:add, left, right}), do: _calculate(left) + _calculate(right)
defp _calculate({:subtract, left, right}), do: _calculate(left) - _calculate(right)
defp _calculate({:multiply, left, right}), do: _calculate(left) * _calculate(right)
defp _calculate({:divide, left, right}), do: _calculate(left) / _calculate(right)

end
``````

I borrowed the number parsing from the previous example and used a Regex to extract the operator. The Regex makes the naive assumption that there are spaces between the operands and operator.

``````def calculate(math) do
str = Kernel.to_string(math)
split = Regex.split(~r/ /, str)
( convert = split
|> Enum.map(&(Kernel.to_charlist(&1)))
|> Enum.into([])
|> Enum.map(&(Characters.number(&1)))
)
perform_operation(convert)
end

def number(operator) when operator in ['+', '-', '*', '/'], do: operator
def number([?-|tail]), do: _number_digits(tail, 0) * -1
def number([?+|tail]), do: _number_digits(tail, 0)
def number(str), do: _number_digits(str, 0)

defp _number_digits([], value), do: value
defp _number_digits([ digit | tail], value) when digit in '0123456789' do
_number_digits(tail, value * 10 + (digit - ?0))
end
defp _number_digits([non_digit|_], _) do
raise "Invalid digit #{[non_digit]}"
end

def perform_operation([num1, '+', num2]), do: num1 + num2
def perform_operation([num1, '-', num2]), do: num1 - num2
def perform_operation([num1, '*', num2]), do: num1 * num2
def perform_operation([num1, '/', num2]), do: num1 / num2
``````

Reading the other solutions I figured out I fell back to thinking in Python. Thanks for this forum!

```defmodule Parse do

#http://www.elixre.uk/ to build regexes
@term_regex ~r/([0-9]+)\s*([\+\-\*\/])\s*([0-9]+)/
@char_to_operation %{"+" => &Kernel.+/2,
"-" => &Kernel.-/2,
"*" => &Kernel.*/2,
"/" => &Kernel.//2}

# requires a chr list as argument! string does not match
def number(str), do: _parse_number(str, 0)

defp _parse_number([], value), do: value

defp _parse_number([ digit | tail], value)
when digit in ?0..?9 do
_parse_number(tail, value* 10 + digit - ?0)
end

defp _parse_number([ non_digit | _ ], _) do
IO.puts "invalid digit #{[non_digit]}."
end

def calculate(str) do
if !Regex.match?(@term_regex, str) do
raise "Input string in wrong format, was '#{str}', should match '#{Regex.source(@term_regex)}'"
end
# scan finds all matches, does not stop after first pass
[[a, op, b]] = Regex.scan(@term_regex, str, [capture: :all_but_first])
@char_to_operation[op].(number(to_charlist a), number(to_charlist b))
end
end

```

Combining the solutions from Karlo Smid and Daniel Ashton is really concise:

```def calculate_by_regex_match(expression) do
case Regex.named_captures(~r/(?<first>[0-9]\d*)\s*(?<operand>[\+-\\\/])\s*0*(?<second>[0-9]\d*)/, expression) do
%{"first" => a, "operand" => op, "second" => b} ->
apply :erlang, String.to_atom(op), [String.to_integer(a), String.to_integer(b)]
_ -> raise "Not parsable input, "
end
end
```
``````defmodule Chapter11 do
import Integer, only: [parse: 1]
defmodule Exercise4 do
def calculate(list) do
[n1, <<op::utf8>>, n2] = List.to_string(list) |> String.split(" ")
[{n1, _}, {n2, _}] = [parse(n1), parse(n2)]
case op do
?+ -> n1 + n2
?- -> n1 - n2
?/ -> div(n1, n2)
?* -> n1 * n2
end
end
end
end
``````

Bringing regex into this one would make sense

```defmodule MyString do

def calculate(expression) do
{expression, x} = _parse_number(expression, 0)
expression = trim_space(expression)
[operator | expression] = expression
expression = trim_space(expression)
{_, y} = _parse_number(expression, 0)
_calculate(x, operator, y)
end

def _calculate(x, ?+, y), do: x + y
def _calculate(x, ?-, y), do: x - y
def _calculate(x, ?*, y), do: x * y
def _calculate(x, ?/, y), do: x / y

def trim_space([?\s | expression]), do: trim_space(expression)
def trim_space(expression), do: expression

def _parse_number([], number) do
{[], number}
end

def _parse_number([char | rest], number) when char in ?0..?9 do
_parse_number(rest, number*10 + char - ?0)
end

def _parse_number(rest, number) do
{rest, number}
end

end
```

My solution :)

``````  def calculate(list), do: calculate(list, 0)
def calculate([], value), do: value
def calculate([digit | tail], value) when digit in '0123456789', do: calculate(tail, value * 10 + digit - ?0)
def calculate([?+ | tail], value), do: value + calculate(tail, 0)
def calculate([?- | tail], value), do: value - calculate(tail, 0)
def calculate([?* | tail], value), do: value * calculate(tail, 0)
def calculate([?/ | tail], value), do: value / calculate(tail, 0)
def calculate([_head | tail], value), do: calculate(tail, value)
``````

I do not feel proud of my solution, as it is just pedestrian compared to all the other ones, but I thought it met the requirements of the problem stated:

```defmodule MyCalc do
@spec calculate(maybe_improper_list) :: integer
def calculate(expr) do
case String.split(List.to_string(expr)) do
[term1, "+", term2] -> String.to_integer(term1) + String.to_integer(term2)
[term1, "-", term2] -> String.to_integer(term1) - String.to_integer(term2)
[term1, "*", term2] -> String.to_integer(term1) * String.to_integer(term2)
[term1, "/", term2] -> String.to_integer(term1) / String.to_integer(term2)
end
end
end
```

If there are no spaces however, it does not work.

Seems I overused guard clauses a bit.

```defmodule Calc do

def calculate(statement) do
statement
|> parse({nil, nil, nil})
|> resolve()
end

defp parse('', parsed), do: parsed
defp parse([c | rest], parsed) when (not c in ?0..?9) and (not c in '+-*/') do
parse(rest, parsed)
end
defp parse([c | rest], {nil, a, nil}) when c in '+-*/' do
parse(rest, {c, a, nil})
end
defp parse([c | rest], {nil, a, nil}) when c in ?0..?9 do
parse(rest, {nil, (a || 0) * 10 + (c - ?0), nil})
end
defp parse([c | rest], { op, a,   b}) when c in ?0..?9 do
parse(rest, {op, a, (b || 0) * 10 + (c - ?0)})
end

defp resolve({?+, a, b}), do: a + b
defp resolve({?-, a, b}), do: a - b
defp resolve({?*, a, b}), do: a * b
defp resolve({?/, a, b}), do: a / b

end
```

My solution ended up coming surprisingly similar to that of Dan Rees-Jones:

``````def calculate(list), do:
calculate(list, [], [], [])

def calculate([h|t], x, [], [])
when h in ?0..?9, do:
calculate(t, [h|x], [], [])

def calculate([h|t], x, [], [])
when h === ?+, do:
calculate(t, x, [], &+/2)
def calculate([h|t], x, [], [])
when h === ?-, do:
calculate(t, x, [], &-/2)
def calculate([h|t], x, [], [])
when h === ?*, do:
calculate(t, x, [], &*/2)
def calculate([h|t], x, [], [])
when h === ?/, do:
calculate(t, x, [], &//2)

def calculate([h|t], x, y, operand)
when h in ?0..?9, do:
calculate(t, x, [h|y], operand)

def calculate([], x, y, operand) do
x = x |> Enum.reverse |> List.to_integer
y = y |> Enum.reverse |> List.to_integer
operand.(x, y)
end
``````
``````
def eval(str) do
case Enum.reduce(str, {0, 0, 0}, fn (x, acc) ->
case acc do
{a1, 0, a} when x in '+-*/' -> {a1, x, a}
{a,0, _} when x >= ?0 and x <= ?9 -> {a*10 + (x - ?0), 0, 0}
{a1,op, a} when x >= ?0 and x <= ?9 -> {a1, op, a*10 + (x - ?0)}
_-> acc
end
end) do
{a, ?+, b} -> a + b
{a, ?-, b} -> a - b
{a, ?*, b} -> a * b
{a, ?/, b} -> a / b
end
end

``````

Used a regex to parse out the numbers and operator.

``````defmodule Calculator do
def calculate(str) do
_calc(Regex.run(~r/(\d+)\s*([+-\/*])\s*(\d+)/, str))
end

defp _calc([_, left, op, right]) do
_calc(String.to_integer(left), op, String.to_integer(right))
end

defp _calc(left, "+", right), do: left + right
defp _calc(left, "-", right), do: left - right
defp _calc(left, "/", right), do: left / right
defp _calc(left, "*", right), do: left * right
end
``````

``````
defmodule Calcul do

def calculation(x) do
cond do
?+ in x -> sum?(x)
?* in x -> prod?(x)
?- in x -> subs?(x)
?/ in x -> div?(x)
end
end

# SUM
defp sum?(x) do
l = Enum.split_while(x, &(&1 != ?+))
List.to_integer(elem(l,0)) + List.to_integer(elem(l,1)-- '+')
end
# Division
defp div?(x) do
l = Enum.split_while(x, &(&1 != ?/))
div(List.to_integer(elem(l,0)), List.to_integer(elem(l,1)-- '/'))
end
#subtraction
defp subs?(x) do
l = Enum.split_while(x, &(&1 != ?-))
List.to_integer(elem(l,0)) - List.to_integer(elem(l,1)-- '-')
end

defp prod?(x) do
l = Enum.split_while(x, &(&1 != ?*))
List.to_integer(elem(l,0)) * List.to_integer(elem(l,1)-- '*')
end

end

``````
```def calculate(list) do
[num1, op, num2] = Enum.chunk_by(list, &(&1 in '+-*/'))
calc(op, List.to_integer(num1--' '), List.to_integer(num2--' '))
end

defp calc('+', num1, num2), do: num1 + num2
defp calc('-', num1, num2), do: num1 - num2
defp calc('*', num1, num2), do: num1 * num2
defp calc('/', num1, num2), do: num1 / num2
```
``````defmodule MyStrings do
def calculate(str), do: calculator(Enum.chunk_by( str, &Enum.member?([42,43,45,47], &1)))

def calculator([a,'+',c]), do: l_to_i(a) + l_to_i(c)
def calculator([a,'-',c]), do: l_to_i(a) - l_to_i(c)
def calculator([a,'*',c]), do: l_to_i(a) * l_to_i(c)
def calculator([a,'/',c]), do: l_to_i(a) / l_to_i(c)

def l_to_i(list), do: List.to_string(list) |> String.trim() |> String.to_integer()
end

``````
You must be logged in to comment