Skip to content

Commit

Permalink
Update documentation
Browse files Browse the repository at this point in the history
- Add module documentation from README
- Make all doctests pass
- Update README from module documentation
- Add inline doctest examples for most methods
- remove `N: Clone` default bound
  • Loading branch information
coriolinus committed Aug 7, 2018
1 parent 56c4e94 commit 8180199
Show file tree
Hide file tree
Showing 3 changed files with 425 additions and 79 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "counter"
version = "0.4.1"
version = "0.4.2"
authors = ["Peter Goodspeed-Niklaus <peter.r.goodspeedniklaus@gmail.com>"]
description = "Simple package to count generic iterables"
repository = "https://github.com/coriolinus/counter-rs"
Expand All @@ -11,3 +11,6 @@ license = "MIT"

[dependencies]
num-traits = "0.2"

[dev-dependencies]
maplit = "1.0"
52 changes: 34 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
# Counter

Simple counter library for Rust iterables. Inspired by, and largely mimicing the API of, Python's [Counter](https://docs.python.org/3.5/library/collections.html#collections.Counter).
Counter counts recurrent elements of iterables. It is based on [the Python implementation](https://docs.python.org/3.5/library/collections.html#collections.Counter).

## Examples

### Just count an iterable

```rust
let char_counts = Counter::init("barefoot".chars());
let counts_counts = Counter::init(char_counts.values());
use counter::Counter;
let char_counts = "barefoot".chars().collect::<Counter<_>>();
let counts_counts = char_counts.values().collect::<Counter<_>>();
```

### Updates are simple
### Update a count

```rust
let mut counts = Counter::init("able babble table babble rabble table able fable scrabble".split_whitespace());
let mut counts = "able babble table babble rabble table able fable scrabble"
.split_whitespace().collect::<Counter<_>>();
// add or subtract an iterable of the same type
counts += "cain and abel fable table cable".split_whitespace();
// or add or subtract from another Counter of the same type
let other_counts = Counter::init("scrabble cabbie fable babble".split_whitespace());
let other_counts = "scrabble cabbie fable babble"
.split_whitespace().collect::<Counter<_>>();
let difference = counts - other_counts;
```

Expand All @@ -27,8 +30,7 @@ let difference = counts - other_counts;
`most_common_ordered()` uses the natural ordering of keys which are `Ord`.

```rust
let by_common = Counter::init("eaddbbccc".chars())
.most_common_ordered();
let by_common = "eaddbbccc".chars().collect::<Counter<_>>().most_common_ordered();
let expected = vec![('c', 3), ('b', 2), ('d', 2), ('a', 1), ('e', 1)];
assert!(by_common == expected);
```
Expand All @@ -38,24 +40,26 @@ assert!(by_common == expected);
For example, here we break ties reverse alphabetically.

```rust
let counter = Counter::init("eaddbbccc".chars());
let counter = "eaddbbccc".chars().collect::<Counter<_>>();
let by_common = counter.most_common_tiebreaker(|&a, &b| b.cmp(&a));
let expected = vec![('c', 3), ('d', 2), ('b', 2), ('e', 1), ('a', 1)];
assert!(by_common == expected);
```

### Treat it like a Map

`Counter<T>` implements `Deref<Target=HashMap<T, usize>>` and
`DerefMut<Target=HashMap<T, usize>>`, which means that you can perform any operations
`Counter<T, N>` implements `Deref<Target=HashMap<T, N>>` and
`DerefMut<Target=HashMap<T, N>>`, which means that you can perform any operations
on it which are valid for a [`HashMap`](https://doc.rust-lang.org/std/collections/struct.HashMap.html).

```rust
let mut counter = Counter::init("aa-bb-cc".chars());
let mut counter = "aa-bb-cc".chars().collect::<Counter<_>>();
counter.remove(&'-');
assert!(counter == Counter::init("aabbcc".chars()));
assert!(counter == "aabbcc".chars().collect::<Counter<_>>());
```

## Advanced Usage

### Count any iterable which is `Hash + Eq`

You can't use the `most_common*` functions unless T is also `Clone`, but simple counting works fine on a minimal data type.
Expand Down Expand Up @@ -86,11 +90,23 @@ let intys = vec![
Inty::new(9),
];

let inty_counts = Counter::init(intys);
println!("{:?}", inty_counts.map);
let inty_counts = intys.iter().collect::<Counter<_>>();
println!("{:?}", inty_counts);
// {Inty { i: 8 }: 2, Inty { i: 0 }: 3, Inty { i: 9 }: 1, Inty { i: 3 }: 1,
// Inty { i: 7 }: 1, Inty { i: 6 }: 1, Inty { i: 5 }: 1}
assert!(inty_counts.map.get(&Inty { i: 8 }) == Some(&2));
assert!(inty_counts.map.get(&Inty { i: 0 }) == Some(&3));
assert!(inty_counts.map.get(&Inty { i: 6 }) == Some(&1));
assert!(inty_counts.get(&Inty { i: 8 }) == Some(&2));
assert!(inty_counts.get(&Inty { i: 0 }) == Some(&3));
assert!(inty_counts.get(&Inty { i: 6 }) == Some(&1));
```

### Use your own type for the count

Sometimes `usize` just isn't enough. If you find yourself overflowing your
machine's native size, you can use your own type. Here, we use an `i8`, but
you can use most numeric types, including bignums, as necessary.

```rust
let counter: Counter<_, i8> = "abbccc".chars().collect();
let expected: HashMap<char, i8> = [('a', 1), ('b', 2), ('c', 3)].iter().cloned().collect();
assert!(counter.into_map() == expected);
```
Loading

0 comments on commit 8180199

Please sign in to comment.