From 035b8a2561644afe7e222b8ddff4f6f08d7eaf91 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Thu, 8 Mar 2018 13:52:10 -0500 Subject: [PATCH] lunchtime elixir --- elixir/pangram/README.md | 50 ++++++ elixir/pangram/pangram.exs | 19 +++ elixir/pangram/pangram_test.exs | 62 +++++++ elixir/scrabble-score/README.md | 81 +++++++++ elixir/scrabble-score/scrabble.exs | 40 +++++ elixir/scrabble-score/scrabble_score_test.exs | 50 ++++++ elixir/simple-linked-list/README.md | 63 +++++++ elixir/simple-linked-list/linked_list.exs | 83 +++++++++ .../simple-linked-list/linked_list_test.exs | 157 ++++++++++++++++++ elixir/sublist/sublist.exs | 27 +++ elixir/sublist/sublist_test.exs | 38 ++--- elixir/sum-of-multiples/README.md | 50 ++++++ elixir/sum-of-multiples/sum_of_multiples.exs | 11 ++ .../sum_of_multiples_test.exs | 64 +++++++ 14 files changed, 776 insertions(+), 19 deletions(-) create mode 100644 elixir/pangram/README.md create mode 100644 elixir/pangram/pangram.exs create mode 100644 elixir/pangram/pangram_test.exs create mode 100644 elixir/scrabble-score/README.md create mode 100644 elixir/scrabble-score/scrabble.exs create mode 100644 elixir/scrabble-score/scrabble_score_test.exs create mode 100644 elixir/simple-linked-list/README.md create mode 100644 elixir/simple-linked-list/linked_list.exs create mode 100644 elixir/simple-linked-list/linked_list_test.exs create mode 100644 elixir/sum-of-multiples/README.md create mode 100644 elixir/sum-of-multiples/sum_of_multiples.exs create mode 100644 elixir/sum-of-multiples/sum_of_multiples_test.exs diff --git a/elixir/pangram/README.md b/elixir/pangram/README.md new file mode 100644 index 0000000..3f339a3 --- /dev/null +++ b/elixir/pangram/README.md @@ -0,0 +1,50 @@ +# Pangram + +Determine if a sentence is a pangram. A pangram (Greek: παν γράμμα, pan gramma, +"every letter") is a sentence using every letter of the alphabet at least once. +The best known English pangram is: +> The quick brown fox jumps over the lazy dog. + +The alphabet used consists of ASCII letters `a` to `z`, inclusive, and is case +insensitive. Input will not contain non-ASCII symbols. + +## Running tests + +Execute the tests with: + +```bash +$ elixir pangram_test.exs +``` + +### Pending tests + +In the test suites, all but the first test have been skipped. + +Once you get a test passing, you can unskip the next one by +commenting out the relevant `@tag :pending` with a `#` symbol. + +For example: + +```elixir +# @tag :pending +test "shouting" do + assert Bob.hey("WATCH OUT!") == "Whoa, chill out!" +end +``` + +Or, you can enable all the tests by commenting out the +`ExUnit.configure` line in the test suite. + +```elixir +# ExUnit.configure exclude: :pending, trace: true +``` + +For more detailed information about the Elixir track, please +see the [help page](http://exercism.io/languages/elixir). + +## Source + +Wikipedia [https://en.wikipedia.org/wiki/Pangram](https://en.wikipedia.org/wiki/Pangram) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/elixir/pangram/pangram.exs b/elixir/pangram/pangram.exs new file mode 100644 index 0000000..dc8fbcd --- /dev/null +++ b/elixir/pangram/pangram.exs @@ -0,0 +1,19 @@ +defmodule Pangram do + @doc """ + Determines if a word or sentence is a pangram. + A pangram is a sentence using every letter of the alphabet at least once. + + Returns a boolean. + + ## Examples + + iex> Pangram.pangram?("the quick brown fox jumps over the lazy dog") + true + + """ + + @spec pangram?(String.t()) :: boolean + def pangram?(sentence) do + Enum.all?(?a..?z, fn c -> c in String.to_charlist(String.downcase(sentence)) end) + end +end diff --git a/elixir/pangram/pangram_test.exs b/elixir/pangram/pangram_test.exs new file mode 100644 index 0000000..4c6e208 --- /dev/null +++ b/elixir/pangram/pangram_test.exs @@ -0,0 +1,62 @@ +if !System.get_env("EXERCISM_TEST_EXAMPLES") do + Code.load_file("pangram.exs", __DIR__) +end + +ExUnit.start() +ExUnit.configure(trace: true) + +defmodule PangramTest do + use ExUnit.Case + + # @tag :pending + test "empty sentence" do + refute Pangram.pangram?("") + end + + @tag :pending + test "pangram with only lower case" do + assert Pangram.pangram?("the quick brown fox jumps over the lazy dog") + end + + @tag :pending + test "missing character 'x'" do + refute Pangram.pangram?("a quick movement of the enemy will jeopardize five gunboats") + end + + @tag :pending + test "another missing character 'x'" do + refute Pangram.pangram?("the quick brown fish jumps over the lazy dog") + end + + @tag :pending + test "pangram with underscores" do + assert Pangram.pangram?("the_quick_brown_fox_jumps_over_the_lazy_dog") + end + + @tag :pending + test "pangram with numbers" do + assert Pangram.pangram?("the 1 quick brown fox jumps over the 2 lazy dogs") + end + + @tag :pending + test "missing letters replaced by numbers" do + refute Pangram.pangram?("7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog") + end + + @tag :pending + test "pangram with mixed case and punctuation" do + assert Pangram.pangram?("Five quacking Zephyrs jolt my wax bed.") + end + + @tag :pending + test "pangram with non ascii characters" do + assert Pangram.pangram?("Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich.") + end + + @tag :pending + test "pangram in alphabet other than ASCII" do + refute Pangram.pangram?( + "Широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства." + ) + end +end diff --git a/elixir/scrabble-score/README.md b/elixir/scrabble-score/README.md new file mode 100644 index 0000000..c8f4bc2 --- /dev/null +++ b/elixir/scrabble-score/README.md @@ -0,0 +1,81 @@ +# Scrabble Score + +Given a word, compute the scrabble score for that word. + +## Letter Values + +You'll need these: + +```text +Letter Value +A, E, I, O, U, L, N, R, S, T 1 +D, G 2 +B, C, M, P 3 +F, H, V, W, Y 4 +K 5 +J, X 8 +Q, Z 10 +``` + +## Examples + +"cabbage" should be scored as worth 14 points: + +- 3 points for C +- 1 point for A, twice +- 3 points for B, twice +- 2 points for G +- 1 point for E + +And to total: + +- `3 + 2*1 + 2*3 + 2 + 1` +- = `3 + 2 + 6 + 3` +- = `5 + 9` +- = 14 + +## Extensions + +- You can play a double or a triple letter. +- You can play a double or a triple word. + +## Running tests + +Execute the tests with: + +```bash +$ elixir scrabble_score_test.exs +``` + +### Pending tests + +In the test suites, all but the first test have been skipped. + +Once you get a test passing, you can unskip the next one by +commenting out the relevant `@tag :pending` with a `#` symbol. + +For example: + +```elixir +# @tag :pending +test "shouting" do + assert Bob.hey("WATCH OUT!") == "Whoa, chill out!" +end +``` + +Or, you can enable all the tests by commenting out the +`ExUnit.configure` line in the test suite. + +```elixir +# ExUnit.configure exclude: :pending, trace: true +``` + +For more detailed information about the Elixir track, please +see the [help page](http://exercism.io/languages/elixir). + +## Source + +Inspired by the Extreme Startup game [https://github.com/rchatley/extreme_startup](https://github.com/rchatley/extreme_startup) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/elixir/scrabble-score/scrabble.exs b/elixir/scrabble-score/scrabble.exs new file mode 100644 index 0000000..bd1b095 --- /dev/null +++ b/elixir/scrabble-score/scrabble.exs @@ -0,0 +1,40 @@ +defmodule Scrabble do + @doc """ + Calculate the scrabble score for the word. + """ + @spec score(String.t()) :: non_neg_integer + def score(word) do + word + |> String.upcase() + |> String.to_charlist() + |> Enum.reduce(0, fn c, acc -> acc + letter_score(c) end) + end + + defp letter_score(letter) do + case letter do + c when c in [?A, ?E, ?I, ?O, ?U, ?L, ?N, ?R, ?S, ?T] -> + 1 + + c when c in [?D, ?G] -> + 2 + + c when c in [?B, ?C, ?M, ?P] -> + 3 + + c when c in [?F, ?H, ?V, ?W, ?Y] -> + 4 + + c when c in [?K] -> + 5 + + c when c in [?J, ?X] -> + 8 + + c when c in [?Q, ?Z] -> + 10 + + _ -> + 0 + end + end +end diff --git a/elixir/scrabble-score/scrabble_score_test.exs b/elixir/scrabble-score/scrabble_score_test.exs new file mode 100644 index 0000000..a94d660 --- /dev/null +++ b/elixir/scrabble-score/scrabble_score_test.exs @@ -0,0 +1,50 @@ +if !System.get_env("EXERCISM_TEST_EXAMPLES") do + Code.load_file("scrabble.exs", __DIR__) +end + +ExUnit.start() +ExUnit.configure(trace: true) + +defmodule ScrabbleScoreTest do + use ExUnit.Case + + # @tag :pending + test "empty word scores zero" do + assert Scrabble.score("") == 0 + end + + @tag :pending + test "whitespace scores zero" do + assert Scrabble.score(" \t\n") == 0 + end + + @tag :pending + test "scores very short word" do + assert Scrabble.score("a") == 1 + end + + @tag :pending + test "scores other very short word" do + assert Scrabble.score("f") == 4 + end + + @tag :pending + test "simple word scores the number of letters" do + assert Scrabble.score("street") == 6 + end + + @tag :pending + test "complicated word scores more" do + assert Scrabble.score("quirky") == 22 + end + + @tag :pending + test "scores are case insensitive" do + assert Scrabble.score("OXYPHENBUTAZONE") == 41 + end + + @tag :pending + test "convenient scoring" do + assert Scrabble.score("alacrity") == 13 + end +end diff --git a/elixir/simple-linked-list/README.md b/elixir/simple-linked-list/README.md new file mode 100644 index 0000000..e4c3211 --- /dev/null +++ b/elixir/simple-linked-list/README.md @@ -0,0 +1,63 @@ +# Simple Linked List + +Write a simple linked list implementation that uses Elements and a List. + +The linked list is a fundamental data structure in computer science, +often used in the implementation of other data structures. They're +pervasive in functional programming languages, such as Clojure, Erlang, +or Haskell, but far less common in imperative languages such as Ruby or +Python. + +The simplest kind of linked list is a singly linked list. Each element in the +list contains data and a "next" field pointing to the next element in the list +of elements. + +This variant of linked lists is often used to represent sequences or +push-down stacks (also called a LIFO stack; Last In, First Out). + +As a first take, lets create a singly linked list to contain the range (1..10), +and provide functions to reverse a linked list and convert to and from arrays. + +When implementing this in a language with built-in linked lists, +implement your own abstract data type. + +## Running tests + +Execute the tests with: + +```bash +$ elixir simple_linked_list_test.exs +``` + +### Pending tests + +In the test suites, all but the first test have been skipped. + +Once you get a test passing, you can unskip the next one by +commenting out the relevant `@tag :pending` with a `#` symbol. + +For example: + +```elixir +# @tag :pending +test "shouting" do + assert Bob.hey("WATCH OUT!") == "Whoa, chill out!" +end +``` + +Or, you can enable all the tests by commenting out the +`ExUnit.configure` line in the test suite. + +```elixir +# ExUnit.configure exclude: :pending, trace: true +``` + +For more detailed information about the Elixir track, please +see the [help page](http://exercism.io/languages/elixir). + +## Source + +Inspired by 'Data Structures and Algorithms with Object-Oriented Design Patterns in Ruby', singly linked-lists. [http://www.brpreiss.com/books/opus8/html/page96.html#SECTION004300000000000000000](http://www.brpreiss.com/books/opus8/html/page96.html#SECTION004300000000000000000) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/elixir/simple-linked-list/linked_list.exs b/elixir/simple-linked-list/linked_list.exs new file mode 100644 index 0000000..45485d0 --- /dev/null +++ b/elixir/simple-linked-list/linked_list.exs @@ -0,0 +1,83 @@ +defmodule LinkedList do + @opaque t :: tuple() + + @doc """ + Construct a new LinkedList + """ + @spec new() :: t + def new() do + # Your implementation here... + end + + @doc """ + Push an item onto a LinkedList + """ + @spec push(t, any()) :: t + def push(list, elem) do + # Your implementation here... + end + + @doc """ + Calculate the length of a LinkedList + """ + @spec length(t) :: non_neg_integer() + def length(list) do + # Your implementation here... + end + + @doc """ + Determine if a LinkedList is empty + """ + @spec empty?(t) :: boolean() + def empty?(list) do + # Your implementation here... + end + + @doc """ + Get the value of a head of the LinkedList + """ + @spec peek(t) :: {:ok, any()} | {:error, :empty_list} + def peek(list) do + # Your implementation here... + end + + @doc """ + Get tail of a LinkedList + """ + @spec tail(t) :: {:ok, t} | {:error, :empty_list} + def tail(list) do + # Your implementation here... + end + + @doc """ + Remove the head from a LinkedList + """ + @spec pop(t) :: {:ok, any(), t} | {:error, :empty_list} + def pop(list) do + # Your implementation here... + end + + @doc """ + Construct a LinkedList from a stdlib List + """ + @spec from_list(list()) :: t + def from_list(list) do + # Your implementation here... + end + + @doc """ + Construct a stdlib List LinkedList from a LinkedList + """ + @spec to_list(t) :: list() + def to_list(list) do + # Your implementation here... + end + + @doc """ + Reverse a LinkedList + """ + @spec reverse(t) :: t + def reverse(list) do + # Your implementation here... + end +end diff --git a/elixir/simple-linked-list/linked_list_test.exs b/elixir/simple-linked-list/linked_list_test.exs new file mode 100644 index 0000000..4a8f4dd --- /dev/null +++ b/elixir/simple-linked-list/linked_list_test.exs @@ -0,0 +1,157 @@ +if !System.get_env("EXERCISM_TEST_EXAMPLES") do + Code.load_file("linked_list.exs", __DIR__) +end + +ExUnit.start() +ExUnit.configure(exclude: :pending, trace: true) + +defmodule LinkedListTest do + use ExUnit.Case + + test "length/1 of new list" do + list = LinkedList.new() + assert LinkedList.length(list) == 0 + end + + @tag :pending + test "empty?/1 of new list" do + list = LinkedList.new() + assert LinkedList.empty?(list) + end + + @tag :pending + test "length/1 of list of 1 datum" do + list = LinkedList.new() |> LinkedList.push(10) + assert LinkedList.length(list) == 1 + end + + @tag :pending + test "empty?/1 of list of 1 datum" do + list = LinkedList.new() |> LinkedList.push(20) + refute LinkedList.empty?(list) + end + + @tag :pending + test "peek/1 of list of 1 datum" do + list = LinkedList.new() |> LinkedList.push(20) + assert LinkedList.peek(list) == {:ok, 20} + end + + @tag :pending + test "peek/1 of list of empty list" do + list = LinkedList.new() + assert LinkedList.peek(list) == {:error, :empty_list} + end + + @tag :pending + test "tail/1 of empty list" do + list = LinkedList.new() + assert {:error, :empty_list} = LinkedList.tail(list) + end + + @tag :pending + test "tail/1 of list of 1 datum" do + list = LinkedList.new() |> LinkedList.push(:hello) + assert {:ok, tail} = LinkedList.tail(list) + assert LinkedList.peek(tail) == {:error, :empty_list} + end + + @tag :pending + test "pushed items are stacked" do + list = + LinkedList.new() + |> LinkedList.push(:a) + |> LinkedList.push(:b) + + assert LinkedList.peek(list) == {:ok, :b} + assert {:ok, list} = LinkedList.tail(list) + assert LinkedList.peek(list) == {:ok, :a} + assert {:ok, list} = LinkedList.tail(list) + assert LinkedList.peek(list) == {:error, :empty_list} + end + + @tag :pending + test "push 10 times" do + list = Enum.reduce(1..10, LinkedList.new(), &LinkedList.push(&2, &1)) + assert LinkedList.peek(list) == {:ok, 10} + assert LinkedList.length(list) == 10 + end + + @tag :pending + test "pop/1 of list of 1 datum" do + list = LinkedList.new() |> LinkedList.push(:a) + assert {:ok, :a, tail} = LinkedList.pop(list) + assert LinkedList.length(tail) == 0 + end + + @tag :pending + test "popping frenzy" do + list = Enum.reduce(11..20, LinkedList.new(), &LinkedList.push(&2, &1)) + assert LinkedList.length(list) == 10 + assert {:ok, 20, list} = LinkedList.pop(list) + assert {:ok, 19, list} = LinkedList.pop(list) + assert {:ok, 18, list} = LinkedList.pop(list) + assert {:ok, 17, list} = LinkedList.pop(list) + assert {:ok, 16, list} = LinkedList.pop(list) + assert {:ok, 15} = LinkedList.peek(list) + assert LinkedList.length(list) == 5 + end + + @tag :pending + test "from_list/1 of empty list" do + list = LinkedList.from_list([]) + assert LinkedList.length(list) == 0 + end + + @tag :pending + test "from_list/1 of 2 element list" do + list = LinkedList.from_list([:a, :b]) + assert LinkedList.length(list) == 2 + assert {:ok, :a, list} = LinkedList.pop(list) + assert {:ok, :b, list} = LinkedList.pop(list) + assert {:error, :empty_list} = LinkedList.pop(list) + end + + @tag :pending + test "to_list/1 of empty list" do + list = LinkedList.new() + assert LinkedList.to_list(list) == [] + end + + @tag :pending + test "to_list/1 of list of 1 datum" do + list = LinkedList.from_list([:mon]) + assert LinkedList.to_list(list) == [:mon] + end + + @tag :pending + test "to_list/1 of list of 2 datum" do + list = LinkedList.from_list([:mon, :tues]) + assert LinkedList.to_list(list) == [:mon, :tues] + end + + @tag :pending + test "reverse/1 of list of 2 datum" do + list = LinkedList.from_list([1, 2, 3]) |> LinkedList.reverse() + assert LinkedList.to_list(list) == [3, 2, 1] + end + + @tag :pending + test "reverse/1 of list of 200 datum" do + list = Enum.to_list(1..200) + linked_list = LinkedList.from_list(list) |> LinkedList.reverse() + assert LinkedList.to_list(linked_list) == Enum.reverse(list) + end + + @tag :pending + test "reverse/1 round trip" do + list = Enum.to_list(1..200) + + linked_list = + LinkedList.from_list(list) + |> LinkedList.reverse() + |> LinkedList.reverse() + + assert LinkedList.to_list(linked_list) == list + end +end diff --git a/elixir/sublist/sublist.exs b/elixir/sublist/sublist.exs index b490ec7..03ee291 100644 --- a/elixir/sublist/sublist.exs +++ b/elixir/sublist/sublist.exs @@ -4,5 +4,32 @@ defmodule Sublist do and if not whether it is equal or unequal to the second list. """ def compare(a, b) do + cond do + a === b -> + :equal + + length(a) == length(b) && a !== b -> + :unequal + + is_sublist?(a, b) -> + :superlist + + is_sublist?(b, a) -> + :sublist + + true -> + :unequal + end + end + + defp is_sublist?(_, []), do: true + defp is_sublist?([], _), do: false + + defp is_sublist?(a = [head | rest], b) do + if head === hd(b) && Enum.take(a, Enum.count(b)) == b do + true + else + is_sublist?(rest, b) + end end end diff --git a/elixir/sublist/sublist_test.exs b/elixir/sublist/sublist_test.exs index 1f3e061..bc417e6 100644 --- a/elixir/sublist/sublist_test.exs +++ b/elixir/sublist/sublist_test.exs @@ -12,98 +12,98 @@ defmodule SublistTest do assert Sublist.compare([], []) == :equal end - @tag :pending + # @tag :pending test "empty is a sublist of anything" do assert Sublist.compare([], [nil]) == :sublist end - @tag :pending + # @tag :pending test "anything is a superlist of empty" do assert Sublist.compare([nil], []) == :superlist end - @tag :pending + # @tag :pending test "1 is not 2" do assert Sublist.compare([1], [2]) == :unequal end - @tag :pending + # @tag :pending test "comparing massive equal lists" do l = Enum.to_list(1..1_000_000) assert Sublist.compare(l, l) == :equal end - @tag :pending + # @tag :pending test "sublist at start" do assert Sublist.compare([1, 2, 3], [1, 2, 3, 4, 5]) == :sublist end - @tag :pending + # @tag :pending test "sublist in middle" do assert Sublist.compare([4, 3, 2], [5, 4, 3, 2, 1]) == :sublist end - @tag :pending + # @tag :pending test "sublist at end" do assert Sublist.compare([3, 4, 5], [1, 2, 3, 4, 5]) == :sublist end - @tag :pending + # @tag :pending test "partially matching sublist at start" do assert Sublist.compare([1, 1, 2], [1, 1, 1, 2]) == :sublist end - @tag :pending + # @tag :pending test "sublist early in huge list" do assert Sublist.compare([3, 4, 5], Enum.to_list(1..1_000_000)) == :sublist end - @tag :pending + # @tag :pending test "huge sublist not in huge list" do assert Sublist.compare(Enum.to_list(10..1_000_001), Enum.to_list(1..1_000_000)) == :unequal end - @tag :pending + # @tag :pending test "superlist at start" do assert Sublist.compare([1, 2, 3, 4, 5], [1, 2, 3]) == :superlist end - @tag :pending + # @tag :pending test "superlist in middle" do assert Sublist.compare([5, 4, 3, 2, 1], [4, 3, 2]) == :superlist end - @tag :pending + # @tag :pending test "superlist at end" do assert Sublist.compare([1, 2, 3, 4, 5], [3, 4, 5]) == :superlist end - @tag :pending + # @tag :pending test "1 and 2 does not contain 3" do assert Sublist.compare([1, 2], [3]) == :unequal end - @tag :pending + # @tag :pending test "partially matching superlist at start" do assert Sublist.compare([1, 1, 1, 2], [1, 1, 2]) == :superlist end - @tag :pending + # @tag :pending test "superlist early in huge list" do assert Sublist.compare(Enum.to_list(1..1_000_000), [3, 4, 5]) == :superlist end - @tag :pending + # @tag :pending test "strict equality needed" do assert Sublist.compare([1], [1.0, 2]) == :unequal end - @tag :pending + # @tag :pending test "recurring values sublist" do assert Sublist.compare([1, 2, 1, 2, 3], [1, 2, 3, 1, 2, 1, 2, 3, 2, 1]) == :sublist end - @tag :pending + # @tag :pending test "recurring values unequal" do assert Sublist.compare([1, 2, 1, 2, 3], [1, 2, 3, 1, 2, 3, 2, 3, 2, 1]) == :unequal end diff --git a/elixir/sum-of-multiples/README.md b/elixir/sum-of-multiples/README.md new file mode 100644 index 0000000..2ee9bd2 --- /dev/null +++ b/elixir/sum-of-multiples/README.md @@ -0,0 +1,50 @@ +# Sum Of Multiples + +Given a number, find the sum of all the unique multiples of particular numbers up to +but not including that number. + +If we list all the natural numbers below 20 that are multiples of 3 or 5, +we get 3, 5, 6, 9, 10, 12, 15, and 18. + +The sum of these multiples is 78. + +## Running tests + +Execute the tests with: + +```bash +$ elixir sum_of_multiples_test.exs +``` + +### Pending tests + +In the test suites, all but the first test have been skipped. + +Once you get a test passing, you can unskip the next one by +commenting out the relevant `@tag :pending` with a `#` symbol. + +For example: + +```elixir +# @tag :pending +test "shouting" do + assert Bob.hey("WATCH OUT!") == "Whoa, chill out!" +end +``` + +Or, you can enable all the tests by commenting out the +`ExUnit.configure` line in the test suite. + +```elixir +# ExUnit.configure exclude: :pending, trace: true +``` + +For more detailed information about the Elixir track, please +see the [help page](http://exercism.io/languages/elixir). + +## Source + +A variation on Problem 1 at Project Euler [http://projecteuler.net/problem=1](http://projecteuler.net/problem=1) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/elixir/sum-of-multiples/sum_of_multiples.exs b/elixir/sum-of-multiples/sum_of_multiples.exs new file mode 100644 index 0000000..2ade545 --- /dev/null +++ b/elixir/sum-of-multiples/sum_of_multiples.exs @@ -0,0 +1,11 @@ +defmodule SumOfMultiples do + @doc """ + Adds up all numbers from 1 to a given end number that are multiples of the factors provided. + """ + @spec to(non_neg_integer, [non_neg_integer]) :: non_neg_integer + def to(limit, factors) do + 0..(limit - 1) + |> Enum.filter(fn c -> Enum.any?(factors, fn m -> rem(c, m) == 0 end) end) + |> Enum.sum() + end +end diff --git a/elixir/sum-of-multiples/sum_of_multiples_test.exs b/elixir/sum-of-multiples/sum_of_multiples_test.exs new file mode 100644 index 0000000..2a15196 --- /dev/null +++ b/elixir/sum-of-multiples/sum_of_multiples_test.exs @@ -0,0 +1,64 @@ +if !System.get_env("EXERCISM_TEST_EXAMPLES") do + Code.load_file("sum_of_multiples.exs", __DIR__) +end + +ExUnit.start() +ExUnit.configure(trace: true) + +defmodule SumOfMultiplesTest do + use ExUnit.Case + + # @tag :pending + test "sum to 1" do + assert SumOfMultiples.to(1, [3, 5]) == 0 + end + + @tag :pending + test "sum to 3" do + assert SumOfMultiples.to(4, [3, 5]) == 3 + end + + @tag :pending + test "sum to 10" do + assert SumOfMultiples.to(10, [3, 5]) == 23 + end + + @tag :pending + test "sum to 20" do + assert SumOfMultiples.to(20, [3, 5]) == 78 + end + + @tag :pending + test "sum to 100" do + assert SumOfMultiples.to(100, [3, 5]) == 2318 + end + + @tag :pending + test "sum to 1000" do + assert SumOfMultiples.to(1000, [3, 5]) == 233_168 + end + + @tag :pending + test "configurable 7, 13, 17 to 20" do + multiples = [7, 13, 17] + assert SumOfMultiples.to(20, multiples) == 51 + end + + @tag :pending + test "configurable 4, 6 to 15" do + multiples = [4, 6] + assert SumOfMultiples.to(15, multiples) == 30 + end + + @tag :pending + test "configurable 5, 6, 8 to 150" do + multiples = [5, 6, 8] + assert SumOfMultiples.to(150, multiples) == 4419 + end + + @tag :pending + test "configurable 43, 47 to 10000" do + multiples = [43, 47] + assert SumOfMultiples.to(10000, multiples) == 2_203_160 + end +end