small medium large xlarge

Dave_gnome_head_isolated_pragsmall
16 Jul 2013, 02:25
Dave Thomas (344 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>

Generic-user-small
03 Aug 2013, 03:27
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.

Twitter-avatar-orangeblau_pragsmall
23 Aug 2013, 13:17
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.

Ac_simpsonized_pragsmall
24 Sep 2013, 03:54
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
Milmazz3_pragsmall
29 Sep 2013, 04:52
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
Mac 128k logic board 96x96_pragsmall
19 Oct 2013, 15:00
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

N609929290_306703_2458_pragsmall
26 Dec 2013, 17:02
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
Generic-user-small
30 Dec 2013, 01:26
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

Generic-user-small
27 Jan 2014, 00:32
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)]
Nathan-6kites_pragsmall
11 Mar 2014, 01:02
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
Generic-user-small
26 Mar 2014, 10:45
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
Patrick_pragsmall
09 Jul 2014, 07:27
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
Generic-user-small
25 Dec 2014, 02:36
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
Generic-user-small
25 Mar 2015, 04:31
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
Generic-user-small
25 Apr 2015, 13:19
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!

Generic-user-small
27 Apr 2015, 12:41
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
Generic-user-small
25 Jul 2015, 07:14
Felipe Juarez Murillo (5 posts)

I ended up with concatenation and in the comments I saw that, if you surround with [ ] you ended up with the same result

defmodule MyList do
  def caesar([], _),            do: []
  def caesar([head | tail], n) when head+n > 122, do: [head + n - 26] ++ caesar(tail, n)
  def caesar([head | tail], n), do: [head + n] ++ caesar(tail, n)
end
Generic-user-small
26 Jul 2015, 14:47
Yevhenii Kurtov (1 post)

What’s the point of substracting 26?

4c5c2c297ed9f4664cfbe7733a011fb2_pragsmall
22 Aug 2015, 12:33
Artem Medeusheyev (8 posts)
defmodule ListFunctions do
  def caesar([], _), do: []
  def caesar([h | t], n), do: [?a + rem(h - ?a + n, ?z - ?a + 1) | caesar(t, n)]
end
  You must be logged in to comment