diff --git a/rust/magazine-cutout/.exercism/config.json b/rust/magazine-cutout/.exercism/config.json new file mode 100644 index 0000000..c9a6b22 --- /dev/null +++ b/rust/magazine-cutout/.exercism/config.json @@ -0,0 +1,17 @@ +{ + "blurb": "Use `HashMap` and the entry API methods to write an anonymous letter.", + "authors": [ + "seanchen1991" + ], + "files": { + "solution": [ + "src/lib.rs" + ], + "test": [ + "tests/magazine-cutout.rs" + ], + "exemplar": [ + ".meta/exemplar.rs" + ] + } +} diff --git a/rust/magazine-cutout/.exercism/metadata.json b/rust/magazine-cutout/.exercism/metadata.json new file mode 100644 index 0000000..4fe7bc2 --- /dev/null +++ b/rust/magazine-cutout/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"magazine-cutout","id":"02f9f776d0cc4b4d90efeea84020a57c","url":"https://exercism.org/tracks/rust/exercises/magazine-cutout","handle":"JBiason","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/magazine-cutout/Cargo.lock b/rust/magazine-cutout/Cargo.lock new file mode 100644 index 0000000..4ebde29 --- /dev/null +++ b/rust/magazine-cutout/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "magazine_cutout" +version = "0.1.0" diff --git a/rust/magazine-cutout/Cargo.toml b/rust/magazine-cutout/Cargo.toml new file mode 100644 index 0000000..b942318 --- /dev/null +++ b/rust/magazine-cutout/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "magazine_cutout" +version = "0.1.0" +edition = "2018" + diff --git a/rust/magazine-cutout/HELP.md b/rust/magazine-cutout/HELP.md new file mode 100644 index 0000000..b4252f8 --- /dev/null +++ b/rust/magazine-cutout/HELP.md @@ -0,0 +1,85 @@ +# Help + +## Running the tests + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run _only ignored_ tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +If you are using Rust 1.51 or later, you can run _all_ tests with + +```bash +$ cargo test -- --include-ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored, use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the online [test documentation][rust-tests]. + +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Submitting your solution + +You can submit your solution using the `exercism submit src/lib.rs` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Rust track's documentation](https://exercism.org/docs/tracks/rust) +- [Exercism's support channel on gitter](https://gitter.im/exercism/support) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The GitHub [track repository][github] is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide]. + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. + +[help-page]: https://exercism.io/tracks/rust/learning +[github]: https://github.com/exercism/rust +[contribution guide]: https://exercism.io/docs/community/contributors \ No newline at end of file diff --git a/rust/magazine-cutout/HINTS.md b/rust/magazine-cutout/HINTS.md new file mode 100644 index 0000000..e18f204 --- /dev/null +++ b/rust/magazine-cutout/HINTS.md @@ -0,0 +1,17 @@ +# Hints + +## General + +- Upon fetching an entry using the `entry` method, the entry can be modified in-place after dereferencing it. + +- The `or_insert` [method](https://doc.rust-lang.org/std/collections/hash_map/enum.Entry.html#method.or_insert) inserts the given value in the case when the entry is vacant, and returns a mutable reference to the value in the entry. + +```rust +*counter.entry(key).or_insert(0) += 1; +``` + +- The `or_default` [method](https://doc.rust-lang.org/std/collections/hash_map/enum.Entry.html#method.or_default) ensures a value is in the entry by inserting the default value if empty, and returns a mutable reference to the value in the entry. + +```rust +*counter.entry(key).or_default() += 1; +``` \ No newline at end of file diff --git a/rust/magazine-cutout/README.md b/rust/magazine-cutout/README.md new file mode 100644 index 0000000..126a1eb --- /dev/null +++ b/rust/magazine-cutout/README.md @@ -0,0 +1,44 @@ +# Magazine Cutout + +Welcome to Magazine Cutout on Exercism's Rust Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +Rust's entry API provides a view into a single entry in map, which may be either a `HashMap` or a `BTreeMap`. The entry may be either occupied and vacant, and the API provides methods to modify the contents of the entry. + +## Instructions + +In this exercise you'll be using a `HashMap`, along with entry API methods, to solve a simple algorithm problem. + +Given `&[&str]` representing the words of a magazine article, and `&[&str]` representing the words of a note you would like to send, can you compose your note by cutting words out of the magazine and pasting them into a letter? + +Notes: + +- This implies physical cutting and pasting; the magazine needs to contain at least as many copies of each word as the note requires. +- Capitalization matters; just because you're pasting together a note composed from words of a magazine doesn't mean you're willing to be ungrammatical. + +You'll start with the following stubbed function signature: + +```rust +pub fn can_construct_note(magazine: &[&str], note: &[&str]) -> bool { + unimplemented!() +} +``` + +Given the following input + +```rust +let magazine = "two times three is not four".split_whitespace().collect::>(); +let note = "two times two is four".split_whitespace().collect::>(); +assert!(!can_construct_note(&magazine, ¬e)); +``` + +The function returns `false` since the magazine only contains one instance of `"two"` when the note requires two of them. + +## Source + +### Created by + +- @seanchen1991 \ No newline at end of file diff --git a/rust/magazine-cutout/src/lib.rs b/rust/magazine-cutout/src/lib.rs new file mode 100644 index 0000000..37dab03 --- /dev/null +++ b/rust/magazine-cutout/src/lib.rs @@ -0,0 +1,31 @@ +// This stub file contains items which aren't used yet; feel free to remove this module attribute +// to enable stricter warnings. +#![allow(unused)] + +use std::collections::HashMap; + +pub fn can_construct_note(magazine: &[&str], note: &[&str]) -> bool { + let mut words_on_magazine: HashMap<&str, u16> = HashMap::new(); + magazine.iter().for_each(|word| { + let count = if words_on_magazine.contains_key(word) { + *words_on_magazine.get(word).unwrap() + } else { + 0 + }; + words_on_magazine.insert(word, count + 1); + }); + + for note_word in note { + if !words_on_magazine.contains_key(note_word) { + return false; + } else { + let count = words_on_magazine.get(note_word).unwrap() - 1; + if count > 0 { + words_on_magazine.insert(note_word, count); + } else { + words_on_magazine.remove(note_word); + } + } + } + true +} diff --git a/rust/magazine-cutout/tests/magazine-cutout.rs b/rust/magazine-cutout/tests/magazine-cutout.rs new file mode 100644 index 0000000..fe4ba34 --- /dev/null +++ b/rust/magazine-cutout/tests/magazine-cutout.rs @@ -0,0 +1,60 @@ +use magazine_cutout::*; + +#[test] +fn test_example_works() { + let magazine = "two times three is not four" + .split_whitespace() + .collect::>(); + let note = "two times two is four" + .split_whitespace() + .collect::>(); + assert!(!can_construct_note(&magazine, ¬e)); +} + +#[test] +fn test_fn_returns_true_for_good_input() { + let magazine = "The metro orchestra unveiled its new grand piano today. Its donor paraphrased Nathn Hale: \"I only regret that I have but one to give \"".split_whitespace().collect::>(); + let note = "give one grand today." + .split_whitespace() + .collect::>(); + assert!(can_construct_note(&magazine, ¬e)); +} + +#[test] +fn test_fn_returns_false_for_bad_input() { + let magazine = "I've got a lovely bunch of coconuts." + .split_whitespace() + .collect::>(); + let note = "I've got som coconuts" + .split_whitespace() + .collect::>(); + assert!(!can_construct_note(&magazine, ¬e)); +} + +#[test] +fn test_case_sensitivity() { + let magazine = "i've got some lovely coconuts" + .split_whitespace() + .collect::>(); + let note = "I've got some coconuts" + .split_whitespace() + .collect::>(); + assert!(!can_construct_note(&magazine, ¬e)); + + let magazine = "I've got some lovely coconuts" + .split_whitespace() + .collect::>(); + let note = "i've got some coconuts" + .split_whitespace() + .collect::>(); + assert!(!can_construct_note(&magazine, ¬e)); +} + +#[test] +fn test_magzine_has_more_than_words_available_than_needed() { + let magazine = "Enough is enough when enough is enough" + .split_whitespace() + .collect::>(); + let note = "enough is enough".split_whitespace().collect::>(); + assert!(can_construct_note(&magazine, ¬e)); +}