0
votes

Trying to level up my Elixir understanding by doing algo/leetCode style problems using Elixir.

As I'm a relatively new programmer (around a year in) and was trained on traditionally OOP languages like Ruby and JS, it's still somewhat hard for me to wrap my head around doing algo questions in a functional paradigm, though I felt I understood the Udemy course I took on Elixir/Phoenix.

I wrote a solution to the LeetCode "valid anagram" problem using Elixir and Repl and wanted to see if people had any ideas for improving/understanding the problem or if there was a best approach way of thinking for this problem.

For an answer, I'd take a code review, a book recommendation or even just suggestions of what I could do differently.

Thank you for your time and hope this (my first question on this site) is clear.



###

Given two strings s and t , write a function to determine if t is an anagram of s.

Example 1:

Input: s = "anagram", t = "nagaram"
Output: true
Example 2:

Input: s = "rat", t = "car"
Output: false
Note:
You may assume the string contains only lowercase alphabets.

###

defmodule Algos do
  
  def is_anagram(str1, str2) do
    case String.length(str1) == String.length(str2) do
      false ->
        IO.puts(false)
      true ->
        both_trackers(str1, str2)
        |> check_trackers
        |> IO.puts
    end
  end

  def both_trackers(str1, str2) do
    t1 = make_tracker(str1)
    t2 = make_tracker(str2)
    {t1, t2}
  end

  def check_trackers({t1, t2}) do
    Map.keys(t1)
    |> Enum.reduce_while(true, fn x, acc -> 
    if t1[x] == t2[x], do: {:cont, acc}, else: {:halt, false}
    end)
  end

  def make_tracker(str) do
    tracker = String.split(str, "", trim: true)
    |> Enum.reduce(%{}, 
      fn x,acc -> Map.merge(acc, 
        case !!acc[x] do
          false ->
            %{x => 1}
          true ->
            %{x => acc[x] + 1}
        end
      ) 
      end
      )
    tracker
  end

end

Algos.is_anagram("sloop ", "pools")

1
Basically you need to construct a frequency histogram for each string then test if the two histograms pattern match.GavinBrelstaff
["anagram", "nagar AM"] |> Enum.map(& &1 |> String.replace(~r|\W|, "") |> String.downcase() |> to_charlist() |> Enum.sort()) |> Enum.reduce(&Kernel.==/2) ⇐ this would eliminate all non-letters, downcase the inputs, convert strings to charlists, sort them and compare the results.Aleksei Matiushkin

1 Answers

2
votes

New elixir has Enum.frequencies, which generates a histogram from an enumerable, which basically solves this problem out of the box:

defmodule Algos do
  def anagram?(a, b) do
    Enum.frequencies(to_charlist(a)) == Enum.frequencies(to_charlist(b))
  end
end

Algos.anagram?("a gentleman", "elegant man") # => true
Algos.anagram?("alice", "bob") # => false