16 Jul 2013, 02:25
Dave_gnome_head_isolated_pragsmall

Dave Thomas (342 posts)

  • Write anagram?(word1, word2) that returns true if its parameters are anagrams.

A Possible Solution</summary>

defmodule MyString do

  def anagram(sqs1, sqs2), do: Enum.sort(sqs1) == Enum.sort(sqs2)

end

IO.inspect MyString.anagram('cat', 'act')                    #=> true
IO.inspect MyString.anagram('cat', 'actor')                  #=> false
IO.inspect MyString.anagram('incorporates', 'procreations')  #=> true

</details>

22 Dec 2013, 17:44
Generic-user-small

Chris Doggett (3 posts)

Here’s what I came up with, not using any built-in libraries. If the two words are anagrams, then adding all the characters in word1 as ints, and subtracting all the characters in word2 should leave you with 0.

defmodule Parse do
  def anagram?(word1, word2) do
    _anagram?(word1, word2, 0) == 0
  end

  defp _anagram?([], [], acc), do: acc
  defp _anagram?([h|_], [], acc), do: acc + h
  defp _anagram?([], [h|_], acc), do: acc - h
  defp _anagram?([h1|t1], [h2|t2], acc) do
    _anagram?(t1, t2, acc + h1 - h2)
  end
end

EDIT: Actually, after thinking about it some more, this won’t work, as it will consider ‘cat’ and ‘bbt’ to be anagrams.

29 Apr 2014, 15:27
Ernie2_pragsmall

Ernie Miller (4 posts)

An alternative I ended up with was to use list subtraction:

def anagram?(word1, word2) do
  (word1 -- word2) == '' and
    (word2 -- word1) == ''
end
24 Sep 2014, 03:45
Generic-user-small

Charles F. Munat (5 posts)

The answer key version does not allow strings or mixed case. This does:

  def anagram?(s1, s2) do
    ( s1
      |> Kernel.to_string
      |> String.downcase
      |> Kernel.to_char_list
      |> Enum.sort
    ) ===
    ( s2
      |> Kernel.to_string
      |> String.downcase
      |> Kernel.to_char_list
      |> Enum.sort
    )
  end
08 Oct 2014, 15:25
Me_pragsmall

Raymond Vernagus (2 posts)

Here’s a version that uses recursion:

defmodule StringCompare do
  def anagram?([], []), do: true
  def anagram?(_word1, []), do: false
  def anagram?([], _word2), do: false
  def anagram?([c | rest], word2) do
    if _in_word(c, word2) do
      anagram?(rest, List.delete(word2, c))
    else
      false
    end
  end

  defp _in_word(_c, []), do: false
  defp _in_word(c, [h | _t]) when c == h, do: true
  defp _in_word(c, [_h | t]), do: _in_word(c, t)
end

IO.puts StringCompare.anagram? 'cat', 'act'                   #=> true
IO.puts StringCompare.anagram? 'cat', 'actor'                 #=> false
IO.puts StringCompare.anagram? 'incorporates', 'procreations' #=> true
12 Nov 2014, 02:34
Generic-user-small

Elliot Finley (11 posts)

A recursive version:

defmodule MyString do
  import List
  def anagram?(word1, word2) when length(word1) != length(word2) do false end
  def anagram?([], []) do true end
  def anagram?(word1, word2) do
    anagram?(delete(word1,first(word1)), delete(word2,first(word1)))
  end
end
26 Nov 2014, 00:25
5971263675_f01d667f5b_z_pragsmall

Stuart Blair (3 posts)

Here’s my solution. After I did it, I came here, saw Dave’s solution and remembered his comment at the end of Ch10 about enumerating being the go-to option. His is certainly smaller. I like Ernie’s solution, it gave me cause to reflect whether I could have written a far simpler (non-recursive) definition of _containsAllTheLettersFrom.

defmodule StringsAndBinaries do
 def anagram?(word, possibleAnagram) do
    _containsAllTheLettersFrom(word, possibleAnagram) and _containsAllTheLettersFrom(possibleAnagram, word)
 end

 defp _containsAllTheLettersFrom([], []), do: true
 defp _containsAllTheLettersFrom(_possibleAnagram, []), do: false
 defp _containsAllTheLettersFrom([], _possibleAnagram), do: false
 defp _containsAllTheLettersFrom([head | tail], possibleAnagram) do
    head in possibleAnagram && _containsAllTheLettersFrom(tail, possibleAnagram -- [head])
 end
 defp _containsAllTheLettersFrom(possibleAnagram, [head | tail]) do
    head in possibleAnagram && _containsAllTheLettersFrom(tail, possibleAnagram -- [head])
 end
end

UPDATE: New version of the above refactored to use a version of _containsAllTheLettersFrom in line with Ernie Miller’s solution:

defmodule StringsAndBinaries do
 def anagram?(word, possibleAnagram) do
    _containsAllTheLettersFrom(word, possibleAnagram) and _containsAllTheLettersFrom(possibleAnagram, word)
  end

  defp _containsAllTheLettersFrom(firstWord, secondWord), do: (firstWord -- secondWord) == ''
end
28 Dec 2014, 21:06
Generic-user-small

Pierre Sugar (56 posts)

defmodule MyString do

  def anagram?(word1, word2), 
    do: sort_and_capitalize(word1) == sort_and_capitalize(word2)
  def sort_and_capitalize(word) do
    List.to_string(word)
    |> String.replace(" ", "")
    |> String.upcase
    |> String.to_char_list
    |> Enum.sort
  end
end

IO.puts MyString.anagram?('Torchwood', 'Doctor Who') #=> true
IO.puts MyString.anagram?('silent', 'listen')        #=> true
IO.puts MyString.anagram?('Army', 'Mary')            #=> true
14 Mar 2015, 15:24
Generic-user-small

Daniel Noll (2 posts)

Here’s what I ended up writing:

defmodule Strings do
  def anagram?(string1, string2) do
    _sorted_graphemes(string1) == _sorted_graphemes(string2)
  end

  defp _sorted_graphemes(string) do
    string
      |> String.downcase   # BUGS
      |> String.graphemes
      |> Enum.sort
  end
end

IO.puts Strings.anagram?("act", "cat")                  #=> true
IO.puts Strings.anagram?("fact", "act")                 #=> false
IO.puts Strings.anagram?("café", "cáfe")                #=> false
IO.puts Strings.anagram?("café", "cáfe")                #=> false

Note that this is the only answer posted thus far that gives the right result for Unicode combining marks on two different characters. ;)

But there are still bugs. String.downcase (and String.upcase) don’t document what locale they’re using and won’t let me pass one in to be completely sure of what it’s doing. So this will either give the wrong results for Turkish strings, or the wrong results for English strings when run on a Turkish system.

23 Apr 2015, 21:39
Matteo_250_pragsmall

Matteo Giachino (2 posts)

is this acceptable?

def anagram?(word1, word2), do: word1 == Enum.reverse word2

or too easy? :)

23 May 2015, 02:30
Img300 copy_pragsmall

Joe Ellis (1 post)

I too went the simple route. Chose to use array substraction since they are char lists after all…

def anagram?(word1, word2), do: length(word1 -- word2) == 0
  You must be logged in to comment