locutus
Version:
Locutus other languages' standard libraries to JavaScript for fun and educational purposes
116 lines (115 loc) • 3.9 kB
JavaScript
const isCollection = (value) => typeof value === 'object' && value !== null;
const objectToArray = (value) => {
if (Array.isArray(value)) {
return value;
}
const converted = Object.values(value).filter((item) => typeof item !== 'undefined');
return converted;
};
const compareValues = (current, next) => {
const currentNum = Number(current);
const nextNum = Number(next);
if (current === next) {
return 0;
}
if (isCollection(current)) {
if (isCollection(next)) {
const currentArray = objectToArray(current);
const nextArray = objectToArray(next);
if (nextArray.length > currentArray.length) {
return 1;
}
if (nextArray.length < currentArray.length) {
return -1;
}
for (let index = 0; index < currentArray.length; index += 1) {
const currentItem = currentArray[index];
const nextItem = nextArray[index];
if (typeof currentItem === 'undefined' || typeof nextItem === 'undefined') {
continue;
}
const comparison = compareValues(currentItem, nextItem);
if (comparison !== 0) {
return comparison;
}
}
return 0;
}
return -1;
}
if (isCollection(next)) {
return 1;
}
if (Number.isNaN(nextNum) && !Number.isNaN(currentNum)) {
if (current === 0) {
return 0;
}
return currentNum < 0 ? 1 : -1;
}
if (Number.isNaN(currentNum) && !Number.isNaN(nextNum)) {
if (next === 0) {
return 0;
}
return nextNum > 0 ? 1 : -1;
}
if (typeof current === 'string' && typeof next === 'string' && Number.isNaN(currentNum) && Number.isNaN(nextNum)) {
return next > current ? 1 : -1;
}
return nextNum > currentNum ? 1 : -1;
};
export function min(...args) {
// discuss at: https://locutus.io/php/min/
// original by: Onno Marsman (https://twitter.com/onnomarsman)
// revised by: Onno Marsman (https://twitter.com/onnomarsman)
// improved by: Jack
// improved by: Thomas Hohn
// note 1: Long code cause we're aiming for maximum PHP compatibility
// example 1: min(1, 3, 5, 6, 7)
// returns 1: 1
// example 2: min([2, 4, 5])
// returns 2: 2
// example 3: min(0, 'hello')
// returns 3: 0
// example 4: min('hello', 0)
// returns 4: 'hello'
// example 5: min(-1, 'hello')
// returns 5: -1
// example 6: min([2, 4, 8], [2, 5, 7])
// returns 6: [2, 4, 8]
// example 7: min({2:'two', 1:'one', 3:'three', 5:'five', 4:'four'})
// returns 7: 'five'
// example 8: min('one', 'two')
// returns 8: 'one'
if (args.length === 0) {
throw new Error('At least one value should be passed to min()');
}
let values;
if (args.length === 1) {
const only = args[0];
if (typeof only === 'undefined' || !isCollection(only)) {
throw new Error('Wrong parameter count for min()');
}
values = objectToArray(only);
if (values.length === 0) {
throw new Error('Array must contain at least one element for min()');
}
}
else {
values = args;
}
const first = values[0];
if (typeof first === 'undefined') {
throw new Error('Array must contain at least one element for min()');
}
let result = first;
for (let index = 1; index < values.length; index += 1) {
const candidate = values[index];
if (typeof candidate === 'undefined') {
continue;
}
if (compareValues(result, candidate) === -1) {
result = candidate;
}
}
return result;
}