small medium large xlarge

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

Generic-user-small
22 Dec 2013, 17:44
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.

Ernie2_pragsmall
29 Apr 2014, 15:27
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
Generic-user-small
24 Sep 2014, 03:45
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
Me_pragsmall
08 Oct 2014, 15:25
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
Generic-user-small
12 Nov 2014, 02:34
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
5971263675_f01d667f5b_z_pragsmall
26 Nov 2014, 00:25
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
Generic-user-small
28 Dec 2014, 21:06
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
Generic-user-small
14 Mar 2015, 15:24
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.

Matteo_250_pragsmall
23 Apr 2015, 21:39
Matteo Giachino (2 posts)

is this acceptable?

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

or too easy? :)

Img300 copy_pragsmall
23 May 2015, 02:30
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
Generic-user-small
08 Aug 2015, 15:09
Julien Lirochon (2 posts)

List subtraction is faster than sorting the lists, but you need to pay attention to length. word1 and word2 must have the same length to be anagrams. ‘foo’ – ‘foooo’ will produce [].

def anagram?(word1, word2) when is_list(word1) and is_list(word2), do: _anagram?(word1, word2)
defp _anagram?(word1, word2) when length(word1) != length(word2), do: false
defp _anagram?(word1, word2), do: length(word1 -- word2) == 0
  You must be logged in to comment