16 Jul 2013, 02:25
Dave_gnome_head_isolated_pragsmall

Dave Thomas (342 posts)

  • An Elixir single quoted string is actually a list of individual character codes. Write a function caesar(list, n) that adds n to each element of the list, but wrapping if the addition results in a character greater than z.

    iex> MyList.caesar('ryvkve', 13)
    ?????? :)
    

A Possible Solution</summary>

defmodule MyList do

  def caesar([], _n), do: []

  def caesar([ head | tail ], n)
    when head+n <= ?z,
    do: [ head+n | caesar(tail, n) ]

  def caesar([ head | tail ], n), 
    do: [ head+n-26 | caesar(tail, n) ]

end

IO.puts MyList.caesar('ryvkve', 13)  #=> elixir

</details>

03 Aug 2013, 03:27
Generic-user-small

Luke Imhoff (6 posts)

Did I miss the ?character => integer somewhere earlier in the book? I ended up going with this since I knew only that single quotes were strings, and that single elements would give the integer:


defmodule MyList do
  @caesar_start hd('a')
  @caesar_end hd('z')
  @caesar_width (@caesar_end - @caesar_start + 1)

  def caesar([], _rotation) do
    []
  end
  def caesar([character | tail], rotation) do
    offset = character - @caesar_start
    rotated_offset = rem(offset + rotation, @caesar_width)
    rotated_character = @caesar_start + rotated_offset

    [rotated_character | caesar(tail, rotation)]
  end
end ---

I’m not sure pre-computing the start and end and width in attributes is faster or the Erlang VM would make the same lift out of the function. I do think this is better than hardcoding the 26 width.

23 Aug 2013, 13:17
Twitter-avatar-orangeblau_pragsmall

Rin Raeuber (1 post)

Alternative without hardcoded width:

defmodule MyList do

  def caesar([], n), do: []

  def caesar([head | tail], n // 0) do
    [_caesar(head, n) | caesar(tail, n) ]
  end

  defp _caesar(char, n) do
    width = ?z - ?a + 1
    ?a + rem(char + n - width, width)
  end

end

Feedback welcome.

24 Sep 2013, 03:54
Ac_simpsonized_pragsmall

Antonio Carlos da Graça Mota Durão de Souza (5 posts)

I used fixed character values.

defmodule MyList do
  def caesar([], _),  do: []

  def caesar([head | tail], salt)
    when head + salt > 122  do
    [96 + (head + salt - 122) | caesar(tail, salt)]
  end

  def caesar([head | tail], salt)
    when head + salt <= 122  do
    [head + salt | caesar(tail, salt)]
  end
end
29 Sep 2013, 04:52
Milmazz3_pragsmall

Milton Mazzarri (1 post)

I think that we can express an alternative solution as result = rem (letter + shift, 26), but first, we need to assume that A=0..Z=25

defmodule MyList do
  def caesar([], _n), do: []

  def caesar([head | tail], n) do
    [do_caesar(head, n) | caesar(tail, n)]
  end

  defp do_caesar(base, n) do
    ?a + rem(base - ?a + n, ?z - ?a + 1)
  end
end
19 Oct 2013, 15:00
Mac 128k logic board 96x96_pragsmall

Roger Turner (7 posts)


defmodule MyList do

  def caesar([], _n), do: []

  def caesar([ head | tail ], n) when head in ?a..?z do
	_caesar(head, n, ?a, tail)
  end

  def caesar([ head | tail ], n) when head in ?A..?Z do
	_caesar(head, n, ?A, tail)
  end

  defp _caesar(alpha, n, first, tail) do 
	[ rem(alpha-first + n, 26) + first  | caesar(tail, n) ]
  end

end

26 Dec 2013, 17:02
N609929290_306703_2458_pragsmall

Tanja Pislar (7 posts)

defmodule MyList do

  def caesar(list, n) do
     map list, &(if (&1 + n) > 122, do: &1 + n - 26, else: &1 + n)
  end

end
30 Dec 2013, 01:26
Generic-user-small

Brynjar Smári Bjarnason (1 post)

Quite simple map

def caesar(coll,n) do
Enum.map(coll, &(rem( &1-?a+n, (?z-?a+1) + ?a) ) end

27 Jan 2014, 00:32
Generic-user-small

Alan Gardner (6 posts)

I ended up with the following because I wasn’t aware of ?z :)

def wrap(char), do: 97 + rem(char-97, 26)
def caesar([], _), do: []
def caesar([head|tail], n), do: [wrap(head+n), caesar(tail, n)]
11 Mar 2014, 01:02
Nathan-6kites_pragsmall

Nathan Feaver (8 posts)

I could use only one map function if I worked this out a little more. I like this solution because I let Enum.map handle the head and tail recursion logic.

defmodule MyList do
  def ceasar(list, n) do
    list
      |> Enum.map(&(&1 + n))
      |> Enum.map(&_char_wrap/1)
  end
  defp _char_wrap(n)
    when n > ?z,
    do: n - 26
  defp _char_wrap(n), do: n
end
26 Mar 2014, 10:45
Generic-user-small

Maximilian Schulz (1 post)

Well, I wasn’t sure about it upfront, but the matching magic seemed like the thing I was looking for. And Elixir seems to be able to compare single element lists pretty well:

  def caesar([], n) do
    []
  end

  def caesar([head | tail], n) when [head + n] > 'z' do
    [head + n - 26 | caesar(tail, n)]
  end

  def caesar([head | tail], n) do
    [head + n | caesar(tail, n)]
  end
09 Jul 2014, 07:27
Patrick_pragsmall

Patrick Oscity (13 posts)

Using our map function with modular arithmetic:

defmodule MyList do
  def map([], fun), do: []
  def map([head | tail], fun), do: [fun.(head) | map(tail, fun)]

  def caesar(string, rot \\ 13) do
    map string, fn char ->
      rem(char - 97 + rot, 26) + 97
    end
  end
end
25 Dec 2014, 02:36
Generic-user-small

Pierre Sugar (56 posts)

defmodule MyList do
  def caesar([], _offset), do: []
  def caesar([head|tail], offs), do: [wrap(head + offs) | caesar(tail, offs)]

  def wrap(value) when value < 32,  do: 122 - rem(32, value)
  def wrap(value) when value > 122, do:  32 + rem(value, 122)
  def wrap(value),                  do: value
end

I use all printable values, so to get Elixir with an offset of 13 the invokation looks like that

IO.puts MyList.caesar('8_\\k\\e', 13) # -> Elixir
25 Mar 2015, 04:31
Generic-user-small

Scott Smith (8 posts)

Interesting problem scope and implementation strategies.

Mine uses module constants; otherwise a mixture of what I see above:

defmodule MyList do
  @wrap ?z + 1 - ?a
  def caesar([], _n), do: []
  def caesar([head | tail], n) when (head + n) <= ?z, do: _recurse(head, tail, n, 0)
  def caesar([head | tail], n)                      , do: _recurse(head, tail, n, @wrap)
  defp _recurse(head, tail, n, offset) do
    [ head + n - offset | caesar(tail, n) ]
  end
end
25 Apr 2015, 13:19
Generic-user-small

Matt Schreck (2 posts)

This is more general, a lot of the above will fail if you give a rotator greater than 26, which could be considered a bug. Also, I think this is quite readable (could be because I wrote it though).

The money shot basically says, “subtract ‘a’s value from the letter we’re looking at, add the rotator, take the remainder of all that when divided by 26, then add ‘a’s value back on”

defmodule MyList do
  def caesar(list,rot), do: _caesar(list, rem(rot,26))
  defp _caesar([],_), do: []
  defp _caesar([head|tail],rot) do
    [ rem( head - ?a + rot, 26) + ?a | caesar(tail,rot)]
  end
end

Edit: Seems Milton Mazzarri above had the same approach. Good on you!

27 Apr 2015, 12:41
Generic-user-small

Francois Roucoux (2 posts)

Using a helper function returning a function:

defmodule MyList do
  defp add_char(n) do
    fn
      c when (c + n > 123) -> c + n - 26
      c -> c + n
    end
  end 
  def caesar(str, n), do: Enum.map(str, add_char(n))
end
  You must be logged in to comment