diff --git a/lib/faker/util.ex b/lib/faker/util.ex index 34bae38d1..f3bf6a44c 100644 --- a/lib/faker/util.ex +++ b/lib/faker/util.ex @@ -272,4 +272,40 @@ defmodule Faker.Util do _ -> raise "Rule #{rule_key} not found or not a function" end end + + @doc """ + Uniquify a list of strings adding an index to each subsequent duplicate. + + ## Examples + + iex> Faker.Util.uniquify(["a", "b", "b", "b", "c", "d", "d", "b"]) + ["a", "b", "b2", "b3", "c", "d", "d2", "b4"] + + """ + @spec uniquify(list) :: list + def uniquify(enumerable) when is_list(enumerable) do + uniq_list(enumerable, %{}) + end + + def uniquify(enumerable) do + raise("Expected a list of strings, received #{inspect(enumerable)}") + end + + defp uniq_list([head | _tail] = list, _set) when not is_binary(head) do + raise("Expected a list of strings, received #{inspect(list)}") + end + + defp uniq_list([head | tail], set) do + value = head + + case set do + %{^value => count} -> + uniq_list(["#{value}#{count + 1}" | tail], Map.put(set, value, count + 1)) + + %{} -> + [head | uniq_list(tail, Map.put(set, value, 1))] + end + end + + defp uniq_list([], _set), do: [] end diff --git a/test/faker/util_test.exs b/test/faker/util_test.exs index 20ef662cd..353d7f2be 100644 --- a/test/faker/util_test.exs +++ b/test/faker/util_test.exs @@ -51,4 +51,26 @@ defmodule Faker.UtilTest do assert Enum.sort(generated_value) == list end) end + + describe "uniquify/1" do + test "list of strings is properly uniquified" do + assert uniquify(["a", "b", "b", "c"]) == ["a", "b", "b2", "c"] + end + + test "list of integers raises an error" do + enumerable = [1, 2, 3, 4] + + assert_raise RuntimeError, + "Expected a list of strings, received #{inspect(enumerable)}", + fn -> uniquify(enumerable) end + end + + test "non-list as input raises an error" do + enumerable = %{invalid: "map"} + + assert_raise RuntimeError, + "Expected a list of strings, received #{inspect(enumerable)}", + fn -> uniquify(enumerable) end + end + end end