Skip to content

Commit

Permalink
Update most_common* functions to return the intermediate Vec
Browse files Browse the repository at this point in the history
The most common operation in testing was to immediately collect it
into a new vector, and there's no plausible way to sort a list
without consuming all items from the list anyway, so we may as well
just return the Vec and call it good.
  • Loading branch information
coriolinus committed Dec 12, 2017
1 parent 10b3d58 commit afe320f
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "counter"
version = "0.2.1"
version = "0.3.0"
authors = ["Peter Goodspeed-Niklaus <peter.r.goodspeedniklaus@gmail.com>"]
description = "Simple package to count generic iterables"
repository = "https://github.com/coriolinus/counter-rs"
Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ let difference = counts - other_counts;

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

```rust
let counter = Counter::init("eaddbbccc".chars());
let by_common = counter.most_common_tiebreaker(|&a, &b| b.cmp(&a)).collect::<Vec<_>>();
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);
```
Expand Down
36 changes: 8 additions & 28 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use std::collections::HashMap;
use std::hash::Hash;

use std::ops::{Add, Sub, AddAssign, SubAssign, BitAnd, BitOr, Deref, DerefMut};

type CounterMap<T> = HashMap<T, usize>;
Expand Down Expand Up @@ -72,12 +71,7 @@ where
T: Hash + Eq + Clone,
{
/// Create an iterator over `(frequency, elem)` pairs, sorted most to least common.
///
/// FIXME: This is pretty inefficient: it copies everything into a vector, sorts
/// the vector, and returns an iterator over the vector. It would be much better
/// to create some kind of MostCommon struct which implements `Iterator` which
/// does all the necessary work on demand. PRs appreciated here!
pub fn most_common(&self) -> ::std::vec::IntoIter<(T, usize)> {
pub fn most_common(&self) -> Vec<(T, usize)> {
use std::cmp::Ordering;
self.most_common_tiebreaker(|ref _a, ref _b| Ordering::Equal)
}
Expand All @@ -87,12 +81,7 @@ where
///
/// In the event that two keys have an equal frequency, use the supplied ordering function
/// to further arrange the results.
///
/// FIXME: This is pretty inefficient: it copies everything into a vector, sorts
/// the vector, and returns an iterator over the vector. It would be much better
/// to create some kind of MostCommon struct which implements `Iterator` which
/// does all the necessary work on demand. PRs appreciated here!
pub fn most_common_tiebreaker<F>(&self, tiebreaker: F) -> ::std::vec::IntoIter<(T, usize)>
pub fn most_common_tiebreaker<F>(&self, tiebreaker: F) -> Vec<(T, usize)>
where
F: Fn(&T, &T) -> ::std::cmp::Ordering,
{
Expand All @@ -108,7 +97,7 @@ where
unequal @ _ => unequal,
}
});
items.into_iter()
items
}
}

Expand All @@ -120,12 +109,7 @@ where
///
/// In the event that two keys have an equal frequency, use the natural ordering of the keys
/// to further sort the results.
///
/// FIXME: This is pretty inefficient: it copies everything into a vector, sorts
/// the vector, and returns an iterator over the vector. It would be much better
/// to create some kind of MostCommon struct which implements `Iterator` which
/// does all the necessary work on demand. PRs appreciated here!
pub fn most_common_ordered(&self) -> ::std::vec::IntoIter<(T, usize)> {
pub fn most_common_ordered(&self) -> Vec<(T, usize)> {
self.most_common_tiebreaker(|ref a, ref b| a.cmp(&b))
}
}
Expand Down Expand Up @@ -422,35 +406,31 @@ mod tests {
#[test]
fn test_most_common() {
let counter = Counter::init("abbccc".chars());
let by_common = counter.most_common().collect::<Vec<_>>();
let by_common = counter.most_common();
let expected = vec![('c', 3), ('b', 2), ('a', 1)];
assert!(by_common == expected);
}

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

#[test]
fn test_most_common_tiebreaker_reversed() {
let counter = Counter::init("eaddbbccc".chars());
let by_common = counter
.most_common_tiebreaker(|&a, &b| b.cmp(&a))
.collect::<Vec<_>>();
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);
}

#[test]
fn test_most_common_ordered() {
let counter = Counter::init("eaddbbccc".chars());
let by_common = counter.most_common_ordered().collect::<Vec<_>>();
let by_common = counter.most_common_ordered();
let expected = vec![('c', 3), ('b', 2), ('d', 2), ('a', 1), ('e', 1)];
assert!(by_common == expected);
}
Expand Down

0 comments on commit afe320f

Please sign in to comment.