sort an array with item closest to two in middle a

2019-08-13 20:02发布

问题:

I have 3 numbers in an array that I want to order so that the item closest to 2 is in the middle, the lowest from two on the left and the highest from two on the right.

example 1 - [2.3, 5.2, 1.2]; should change to [1.2, 2.3, 5.2];

example 2 - [1.1, 2.3, 0.3]; which should change to [0.3, 2.3, 1.1];

example 3 - [1.3, 0.3, 2]; which should change to [0.3, 2, 1.3];

example 4 - [2.2, 2.3, 2.1]; which should change to [2.2, 2.1, 2.3];

Currently I have the following but this is not ordering correctly. This puts the item closest to 2 at the front.

arr.sort(function(a, b){
    return Math.abs(1 - (a - 2)) - Math.abs(1 - (b - 2));
});

Can anyone see how this needs to be changed?

回答1:

You need a three step approach, first sort to get the closest to the given value, shift that value and sort the rest ascending. Then plice the temporary value to index 1.

function sort(array) {
    var temp = array.sort((a, b) => Math.abs(x - a) - Math.abs(x - b)).shift();
    array.sort((a, b) => a - b).splice(1, 0, temp);
    return array;
}

var x = 2;
console.log(sort([0, 1, 2]));
console.log(sort([1, 2, 3]));
console.log(sort([2, 3, 4]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Another solution would be to collect the values with bigger delta in a new array and sort it. Later put the reduced value back to index 1.

Advantage: No superfluous sort, while only one iteration is needed.

function sort(array) {
    var temp = [],
        value = array.reduce((a, b) =>
            Math.abs(x - a) < Math.abs(x - b) ? (temp.push(b), a) : (temp.push(a), b)
        );

    temp.sort((a, b) => a - b).splice(1, 0, value);
    return temp;
}

var x = 2;
console.log(sort([0, 1, 2]));
console.log(sort([1, 2, 3]));
console.log(sort([2, 3, 4]));
.as-console-wrapper { max-height: 100% !important; top: 0; }



回答2:

To easy, sort after distance to 2, then put the first into the second position:

arr.sort((a,b)=>Math.abs(a-2)-Math.abs(b-2));

arr=[arr[1],arr[0],arr[2]];

http://jsbin.com/kifitosopo/edit?console



回答3:

You could do it using one reducer with straight forward rules.

const diff = value => Math.abs(value - 2)

const sort = arr => arr.reduce(([min, closest, max], value) => {
    if(closest !== closest || diff(value) < diff(closest)) [closest, value] = [value, closest]

    if(min !== min || value < min ) min = value
    
    if(max !== max || value > max ) max = value
    
    return [min, closest, max]
    
  }, new Array(3).fill(NaN))


const tests = [
  [2.3, 5.2, 1.2],
  [1.1, 2.3, 0.3],
  [1.3, 0.3, 2],
  [2.2, 2.3, 2.1] 
]

tests.forEach(test => console.log(`[${test.join(', ')}] --> [${sort(test).join(', ')}]`))