Dado este código:

    var minX = minY = maxX = maxY = 0;

    for(var i=0; i<objArray.length; i++){
        if(objArray[i].x < minX){
            minX = objArray[i].x;
        }else if(objArray [i].x > maxX){
            maxX = objArray[i].x;
        }
        if(objArray[i].y < minY){
            minY = objArray[i].y;
        }else if(objArray [i].y > maxY){
            maxY = objArray[i].y;
        }
    }

Funciona, pero no creo que sea muy elegante. Es una lógica simple, pero utiliza 10 líneas de código. ¿Se puede mejorar?

2
DNB5brims 23 ago. 2009 a las 11:08

3 respuestas

La mejor respuesta

Puede usar Math.min y Math.max:

var minX = minY = Number.POSITIVE_INFINITY,
    maxX = maxY = Number.NEGATIVE_INFINITY;

for(var i=0; i<objArray.length; i++){
  minX = Math.min(objArray[i].x, minX);
  minY = Math.min(objArray[i].y, minY);
  maxX = Math.max(objArray[i].x, maxX);
  maxY = Math.max(objArray[i].y, maxY);
}

Para la optimización de la velocidad del bucle, puede almacenar la longitud para calcularla solo una vez:

for(var i=0, len = objArray.length; i<len; i++){
  //...
}

Consulte este artículo para obtener más información sobre la optimización del bucle.

Otro enfoque, solo para "diversión funcional", ya que no lo recomendaría para el rendimiento, podría ser separar los valores x e y en dos matrices utilizando Array.map, y luego llame a las funciones min y max con aplicar:

var allX = objArray.map(function (o) { return o.x; });
var allY = objArray.map(function (o) { return o.y; });

minX = Math.min.apply(Math, allX);
minY = Math.min.apply(Math, allY);
maxX = Math.max.apply(Math, allX);
maxY = Math.max.apply(Math, allY);

¿Cómo funciona esto?

La función apply se utiliza para llamar a otra función, con una contexto y argumentos dados, proporcionados como una matriz. Las funciones min y max pueden tomar un número arbitrario de argumentos de entrada: Math.max (val1, val2, ..., valN)

Así que si la llamamos:

Math.min.apply(Math, [1,2,3,4]);

La función de aplicación ejecutará:

Math.min(1,2,3,4);

Tenga en cuenta que el primer parámetro, el contexto, no es importante para estas funciones, ya que son estáticas, funcionarán independientemente de lo que se pase como contexto.

10
Bill the Lizard 29 jul. 2012 a las 01:11

Todas las respuestas hasta ahora parecen estar usando variables no inicializadas (minX, etc.) en las comparaciones. Aquí hay una solución funcional y elegante:

var minX = anarray.reduce( function(a,b) { return {x : Math.min(a.x,b.x)};}).x;
var minY = anarray.reduce( function(a,b) { return {y : Math.min(a.y,b.y)};}).y;
var maxX = anarray.reduce( function(a,b) { return {x : Math.max(a.x,b.x)};}).x;
var maxY = anarray.reduce( function(a,b) { return {y : Math.max(a.y,b.y)};}).y;

Busque aquí para obtener una explicación de la función de reducción y cómo habilítelo en navegadores que no lo admitan de forma nativa.

1
postfuturist 23 ago. 2009 a las 08:27

Utiliza hasta 10 líneas de código.

Sin embargo, LoC no es una medida de optimización .

Probé los algoritmos anteriores en Firefox 3.5. (Consulte a continuación el caso de prueba).

¡Su código original (método A) fue casi el doble de rápido que el de CMS (método B)! El uso de Math.min hace que su versión sea mucho más legible, y en la mayoría de los casos eso es lo importante. Pero sí introduce más búsquedas y llamadas a funciones, y eso lo ralentiza.

¡La versión de 'diversión funcional' (methodC) fue en realidad considerablemente más rápida que cualquiera de las versiones! Esto fue una sorpresa para mí ya que esta versión tiene que construir dos matrices temporales, pero parece que el buen uso de apply () para hacer todas las comparaciones de una sola vez lo compensa. Esto es, sin embargo, en Firefox, donde hay una implementación nativa de Array.map (). Los navegadores como IE que no tienen esta funcionalidad requieren piratear una versión de JavaScript en el prototipo Array, lo que hizo que el método C fuera tan lento como el método B para mí.

La versión funcional alternativa de Steveth era, como se esperaba, muy lenta; Todos esos objetos temporales cobran un precio.

Al final, lo más rápido que logré fue tomar el método original A y ajustarlo para eliminar el acceso por longitud de bucle, y micro-optimizar los accesos de múltiples propiedades. Sorprendentemente, este (método E) se interrumpió bastante.

Sin embargo, todo esto suele ser muy específico del navegador. Solo probé en un navegador; puede obtener resultados diferentes en otros. Por lo general, la microoptimización no vale la pena y es mejor que elija la opción más legible.

<script type="text/javascript">
    var objArray= [];
    for (var i= 0; i<1000000; i++) {
        objArray.push({'x': Math.floor(Math.random()*100000), 'y': Math.floor(Math.random()*100000)});
    }

    function methodA() {
        var t= new Date();
        var minX = minY = maxX = maxY = 0;
        for(var i=0; i<objArray.length; i++){
                if(objArray[i].x < minX){
                        minX = objArray[i].x;
                }else if(objArray [i].x > maxX){
                        maxX = objArray[i].x;
                }
                if(objArray[i].y < minY){
                        minY = objArray[i].y;
                }else if(objArray [i].y > maxY){
                        maxY = objArray[i].y;
                }
        }
        alert(new Date()-t);
    }
    function methodB() {
        var t= new Date();
        var minX = minY = Number.POSITIVE_INFINITY,
            maxX = maxY = Number.NEGATIVE_INFINITY;
        for(var i=0; i<objArray.length; i++){
          minX = Math.min(objArray[i].x, minX);
          minY = Math.min(objArray[i].y, minY);
          maxX = Math.max(objArray[i].x, maxX);
          maxY = Math.max(objArray[i].y, maxY);
        }
        alert(new Date()-t);
    }
    function methodC() {
        var t= new Date();
        var allX = objArray.map(function (o) { return o.x; });
        var allY = objArray.map(function (o) { return o.y; });

        minX = Math.min.apply(Math, allX);
        minY = Math.min.apply(Math, allY);
        maxX = Math.max.apply(Math, allX);
        maxY = Math.max.apply(Math, allY);
        alert(new Date()-t);
    }
    function methodD() {
        var t= new Date();
        var minX = objArray.reduce( function(a,b) { return {x : Math.min(a.x,b.x)};}).x;
        var minY = objArray.reduce( function(a,b) { return {y : Math.min(a.y,b.y)};}).y;
        var maxX = objArray.reduce( function(a,b) { return {x : Math.max(a.x,b.x)};}).x;
        var maxY = objArray.reduce( function(a,b) { return {y : Math.max(a.y,b.y)};}).y;
        alert(new Date()-t);
    }
    function methodE() {
        var t= new Date();
        var minX = minY = maxX = maxY = 0;
        var o, v;
        for (var i=objArray.length; i-->0;) {
            o= objArray[i];
            v= o.x;
            if (v<minX) minX= v;
            if (v>maxX) maxX= v;
            v= o.y;
            if (v<minY) minY= v;
            if (v>maxY) maxY= v;
        }
        alert(new Date()-t);
    }
</script>
<button onclick="methodA()">A</button>
<button onclick="methodB()">B</button>
<button onclick="methodC()">C</button>
<button onclick="methodD()">D</button>
<button onclick="methodE()">E</button>
5
bobince 23 ago. 2009 a las 10:14