function ranks( x, options ) {
	var missingIndices;
	var noDuplicates;
	var countMissing;
	var totalNoTies;
	var finalRanks;
	var encoding;
	var iPlusOne;
	var ordered;
	var missing;
	var tieRank;
	var method;
	var ranks;
	var opts;
	var xnew;
	var err;
	var n;
	var i;
	var j;

	if ( !isCollection( x ) ) {
		throw new TypeError( format( 'invalid argument. First argument must be an array-like object. Value: `%s`.', x ) );
	}
	opts = {};
	if ( arguments.length > 1 ) {
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}
	method = opts.method || 'average';
	encoding = opts.encoding || [ null, NaN ];
	missing = opts.missing || 'last';

	n = x.length;
	xnew = [];
	for ( i = 0; i < n; i++ ) {
		if ( !contains( encoding, x[ i ] ) ) {
			xnew.push( x[ i ] );
		}
	}
	missingIndices = isMissing( x, encoding );
	n = xnew.length;
	totalNoTies = 0;
	ordered = order( xnew );

	ranks = zeros( n );
	if ( method === 'ordinal' ) {
		for ( i = 0; i < n; i++ ) {
			ranks[ ordered[ i ] ] = i + 1;
		}
	} else {
		noDuplicates = 0;
		for ( i = 0; i < n; i++ ) {
			iPlusOne = i + 1;
			if (
				( i === n - 1 ) ||
				( xnew[ ordered[i] ] !== xnew[ ordered[ iPlusOne ] ] )
			) {
				switch ( method ) {
				case 'min':
					tieRank = iPlusOne - noDuplicates;
					break;
				case 'max':
					tieRank = iPlusOne;
					break;
				case 'dense':
					tieRank = iPlusOne - noDuplicates - totalNoTies;
					totalNoTies += noDuplicates;
					break;
				case 'average':
				default:
					tieRank = iPlusOne - ( 0.5 * noDuplicates );
					break;
				}
				for ( j = i - noDuplicates; j < iPlusOne; j++ ) {
					ranks[ ordered[ j ] ] = tieRank;
				}
				noDuplicates = 0;
			} else {
				noDuplicates += 1;
			}
		}
	}

	if ( missing === 'first' ) {
		countMissing = sum( missingIndices );
		j = 1;
		finalRanks = [];
		for ( i = 0; i < missingIndices.length; i++ ) {
			if ( missingIndices[ i ] ) {
				finalRanks.push( j );
				j += 1;
			} else {
				finalRanks.push( ranks.shift() + countMissing );
			}
		}
		return finalRanks;
	}
	if ( missing === 'last' ) {
		finalRanks = [];
		for ( i = 0; i < missingIndices.length; i++ ) {
			if ( missingIndices[ i ] ) {
				finalRanks.push( i + ranks.length + 1 );
			} else {
				finalRanks.push( ranks.shift() );
			}
		}
		return finalRanks;
	}
	// Case: missing = 'remove'
	return ranks;
}
Computes the sample ranks for the values of an array-like object.

@param {Collection} x - data array
@param {Object} [options] - options object
@param {string} [options.method='average'] - method name determining how ties are treated
@param {string} [options.missing='last'] - determines where missing values go (`first`,`last`, or `remove`)
@param {Array} [options.encoding=[null,NaN]] - array of values encoding missing values
@throws {TypeError} first argument has to be an array-like object
@throws {TypeError} options argument must be an object
@throws {TypeError} must provide valid options
@returns {Array} array containing the computed ranks for the elements of x

@example
var arr = [ 1.1, 2.0, 3.5, 0.0, 2.4 ];
var out = ranks( arr );
// returns [ 2, 3, 5, 1, 4 ]

@example
// Ties are averaged:
arr = [ 2, 2, 1, 4, 3 ];
out = ranks( arr );
// returns [ 2.5, 2.5, 1, 5, 4 ]

@example
// Missing values are placed last:
arr = [ null, 2, 2, 1, 4, 3, NaN, NaN ];
out = ranks( arr );
// returns [ 6, 2.5, 2.5, 1, 5, 4, 7 ,8 ]