Skip to content

Commit 6c7a4ef

Browse files
author
EphemeralDev
committed
First working solution for rust/magazine-cutout
1 parent e56b434 commit 6c7a4ef

File tree

6 files changed

+176
-0
lines changed

6 files changed

+176
-0
lines changed

rust/magazine-cutout/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Generated by Cargo
2+
# will have compiled files and executables
3+
/target/
4+
**/*.rs.bk
5+
6+
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
7+
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
8+
Cargo.lock

rust/magazine-cutout/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[package]
2+
name = "magazine_cutout"
3+
version = "0.1.0"
4+
edition = "2021"

rust/magazine-cutout/HINTS.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Hints
2+
3+
## General
4+
5+
- Upon fetching an entry using the `entry` method, the entry can be modified in-place after dereferencing it.
6+
7+
- 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.
8+
9+
```rust
10+
*counter.entry(key).or_insert(0) += 1;
11+
```
12+
13+
- 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.
14+
15+
```rust
16+
*counter.entry(key).or_default() += 1;
17+
```

rust/magazine-cutout/README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Magazine Cutout
2+
3+
Welcome to Magazine Cutout on Exercism's Rust Track.
4+
If you need help running the tests or submitting your code, check out `HELP.md`.
5+
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
6+
7+
## Introduction
8+
9+
Rust's entry API provides a view into a single entry in map, which may be either a `HashMap` or a `BTreeMap`.
10+
The entry may be either occupied or vacant, and the API provides methods to modify the contents of the entry.
11+
12+
## Instructions
13+
14+
In this exercise you'll be using a `HashMap`, along with entry API methods, to solve a simple algorithm problem.
15+
16+
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?
17+
18+
Notes:
19+
20+
- This implies physical cutting and pasting; the magazine needs to contain at least as many copies of each word as the note requires.
21+
- 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.
22+
23+
You'll start with the following stubbed function signature:
24+
25+
```rust
26+
pub fn can_construct_note(magazine: &[&str], note: &[&str]) -> bool {
27+
unimplemented!()
28+
}
29+
```
30+
31+
Given the following input
32+
33+
```rust
34+
let magazine = "two times three is not four".split_whitespace().collect::<Vec<&str>>();
35+
let note = "two times two is four".split_whitespace().collect::<Vec<&str>>();
36+
assert!(!can_construct_note(&magazine, &note));
37+
```
38+
39+
The function returns `false` since the magazine only contains one instance of `"two"` when the note requires two of them.
40+
41+
The following input will succeed:
42+
43+
```rust
44+
let magazine = "Astronomer Amy Mainzer spent hours chatting with Leonardo DiCaprio for Netflix's 'Don't Look Up'".split_whitespace().collect::<Vec<&str>>();
45+
let note = "Amy Mainzer chatting with Leonardo DiCaprio"
46+
.split_whitespace()
47+
.collect::<Vec<&str>>();
48+
assert!(can_construct_note(&magazine, &note));
49+
```
50+
51+
The function returns `true` since the magazine contains all the words that the note requires.
52+
53+
## Source
54+
55+
### Created by
56+
57+
- @seanchen1991

rust/magazine-cutout/src/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use std::collections::HashMap;
2+
3+
pub fn can_construct_note(magazine: &[&str], note: &[&str]) -> bool {
4+
let mut map = HashMap::new();
5+
6+
for word in magazine {
7+
*map.entry(word).or_insert(0) += 1;
8+
}
9+
10+
for word in note {
11+
*map.entry(word).or_insert(0) -= 1;
12+
13+
if map.values().any(|&k| k < 0) {
14+
return false;
15+
}
16+
}
17+
true
18+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use magazine_cutout::*;
2+
3+
#[test]
4+
fn test_magazine_has_fewer_words_available_than_needed() {
5+
let magazine = "two times three is not four"
6+
.split_whitespace()
7+
.collect::<Vec<&str>>();
8+
let note = "two times two is four"
9+
.split_whitespace()
10+
.collect::<Vec<&str>>();
11+
assert!(!can_construct_note(&magazine, &note));
12+
}
13+
14+
#[test]
15+
#[ignore]
16+
fn test_fn_returns_true_for_good_input() {
17+
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::<Vec<&str>>();
18+
let note = "give one grand today."
19+
.split_whitespace()
20+
.collect::<Vec<&str>>();
21+
assert!(can_construct_note(&magazine, &note));
22+
}
23+
24+
#[test]
25+
#[ignore]
26+
fn test_fn_returns_false_for_bad_input() {
27+
let magazine = "I've got a lovely bunch of coconuts."
28+
.split_whitespace()
29+
.collect::<Vec<&str>>();
30+
let note = "I've got som coconuts"
31+
.split_whitespace()
32+
.collect::<Vec<&str>>();
33+
assert!(!can_construct_note(&magazine, &note));
34+
}
35+
36+
#[test]
37+
#[ignore]
38+
fn test_case_sensitivity() {
39+
let magazine = "i've got some lovely coconuts"
40+
.split_whitespace()
41+
.collect::<Vec<&str>>();
42+
let note = "I've got some coconuts"
43+
.split_whitespace()
44+
.collect::<Vec<&str>>();
45+
assert!(!can_construct_note(&magazine, &note));
46+
47+
let magazine = "I've got some lovely coconuts"
48+
.split_whitespace()
49+
.collect::<Vec<&str>>();
50+
let note = "i've got some coconuts"
51+
.split_whitespace()
52+
.collect::<Vec<&str>>();
53+
assert!(!can_construct_note(&magazine, &note));
54+
}
55+
56+
#[test]
57+
#[ignore]
58+
fn test_magazine_has_more_words_available_than_needed() {
59+
let magazine = "Enough is enough when enough is enough"
60+
.split_whitespace()
61+
.collect::<Vec<&str>>();
62+
let note = "enough is enough".split_whitespace().collect::<Vec<&str>>();
63+
assert!(can_construct_note(&magazine, &note));
64+
}
65+
66+
#[test]
67+
#[ignore]
68+
fn test_magazine_has_one_good_word_many_times_but_still_cant_construct() {
69+
let magazine = "A A A".split_whitespace().collect::<Vec<&str>>();
70+
let note = "A nice day".split_whitespace().collect::<Vec<&str>>();
71+
assert!(!can_construct_note(&magazine, &note));
72+
}

0 commit comments

Comments
 (0)