Git Product home page Git Product logo

stoogesort-rs's Introduction

Ergonomic stooge sort implementation.

Implements 3 methods for stooge-sorting [T]/Vec<T>:

  • .stooge_sort() (for Ord types)
  • .stooge_sort_by() (for everything else; bring your own comparator function!)
  • .stooge_sort_by_key() (also for everything else)

Usage

Add the following to your Cargo.toml,

[dependencies]
stoogesort = "0.2.0"

and import the [Stooge] extension trait.

use stoogesort::Stooge;

Usage should be identical to slice::sort(), slice::sort_by(), and .stooge_sort_by_key().

Examples

Sorting an Ord type using .stooge_sort():

use stoogesort::Stooge;
let mut nums = [3, 2, 1, -5];
nums.stooge_sort();
assert_eq!(nums, [-5, 1, 2, 3]);

Sorting a PartialOrd type using .stooge_sort_by()

use stoogesort::Stooge;
let mut floats = [0.1, 0.0, 1.0, -1.6];
floats.stooge_sort_by(|a, b| a.partial_cmp(b).unwrap());
assert_eq!(floats, [-1.6, 0.0, 0.1, 1.0]);

Sorting strings tagged with numbers at the end:

use stoogesort::Stooge;
let mut s = [ "foo_1", "bar_0", "quux_2" ];
s.stooge_sort_by_key(|t| t.split('_').last().unwrap().parse::<i64>().unwrap());
assert_eq!(s, [ "bar_0", "foo_1", "quux_2" ]);

Acknowledgements

Prior Art (or: "Why do it again?")

It's funny to implement slow algorithms in a "blazing-fast" language!

Also, I wanted to learn how to write a library (and one with a cromulent, natural interface), use traits, and publish to crates.io.

To my knowledge, 2 stooge sort implementations (not counting crates that promise to include stooge sort) already exist:

At risk of sounding rude, I don't like them very much.

stooge

stooge can be forgiven here, as it was explicitly written as a learning project, but it's illustrative.

Pulled from that crate's README (in all its Rust 2015 glory):

extern crate stooge;

fn main() {
	let mut v: Vec<i32> = vec![1, 5, 4, 3];
	stooge::sort(&mut v);
	return v; // [1, 3, 4, 5]
}

The name is clever, but not particularly conducive to production use -- were this a serious project, I would have to write either stooge::sort(v) or sort(v) instead of v.sort(). It's backwards.

The sort() function is also implemented on [T: PartialOrd], which I find unsatisfying. More on that on the next subsection.

sorting_rs

This one is theoretically is intended for 'production' use (judging by the version number), or at least for dissection. However, its interface is still... wonky.

let mut vec = vec![5,3,2,4];
sorting_rs::oddeven_sort(&mut vec);
assert_eq!(vec, &[2,3,4,5]);

There is an obvious receiver here, it should've been a method.

At the same time, it also implements these sorting algorithms on [T] where T: PartialOrd, which I'll now describe my problem with:

PartialOrd's .lt() (used by the < operator), .gt() (used by >), and its "-or-equal-to" variants are not mathematically airtight. Suppose there's an integer type, that, for some reason, has a NaN value. I'll call it NaNInt. NaN is not a number -- it is nonsense to use NaN in a comparison. Since there is at least one pair of NaNInts for which comparison is impossible or nonsensical, they form a partial order. Thus, the NaNInt type can only be PartialOrd. As such:

use std::cmp::Ordering;

let a = NaNInt::from(1);
let b = NaNInt::from(2);
let c = NaNInt::NaN;

assert_eq!(a.partial_cmp(b), Some(Ordering::Less));
assert_eq!(a.partial_cmp(c), None);
assert_eq!(c.partial_cmp(c), None);

Okay, we're good. This makes sense. Now, let's consider what happens when we use .lt() and .gt() on a NaN, keeping in mind that these methods return a [bool], not an [Option].

let a = NaNInt::from(1);
let b = NaNInt::from(2);
let c = NaNInt::NaN;

assert_eq!(c > a, false);
assert_eq!(c < a, false);
assert_eq!(b < c, false);
assert_eq!(b > c, false);
assert_eq!(c > c, false);
assert_eq!(c < c, false);

That's right! It's nonsense. A NaN is never less than or greater than anything else, including itself. This causes sorting on [T: PartialOrd] to be unspecified if it contains incomparable pairs of elements.

Indeed, this is documented (rather indirectly) in [slice::sort_by()].

The comparator function must define a total ordering for the elements in the slice. If the ordering is not total, the order of the elements is unspecified.

For this reason, the standard library instead provides 3 methods (+ variants for unstable (not that stooge sort is stable) and cached) for sorting slices. They are:

  • [slice::sort()]

  • [slice::sort_by()]

  • [slice::sort_by_key()]

Notice the bound Ord on sort() and the distinct lack of one on sort_by(). Also notice the bound Ord on the type parameter K in sort_by_key().

The standard library is protecting you from an attempt to naively sort PartialOrds by making you gaze upon the Wrongness that is .sort_by(|a, b| a.partial_cmp(b).unwrap()) in the sort_by() example.

As such, I've taken the liberty of imitating the standard library in this library. It also makes implementation easy, since I can just copy function signatures and even the code itself at times.

stoogesort-rs's People

Contributors

multiplealiases avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.