He creado un array de objetos como:

var places = [];
var a = {};
a.lat = 12.123;
a.lng = 13.213;
a.city = "New York";

places.push(a);

var b = {};
b.lat = 3.123;
b.lng = 2.213;
b.city = "New York";

places.push(b);

...

Estoy tratando de crear una nueva matriz en la que los filtros de los lugares a los que sólo contiene objetos que no tienen la misma propiedad de la ciudad (lat/lng duplicados están bien). Hay una construida en JS o Jquery función de lograr esto?

  • Sí, mira en [].forEach() o el bucle for.
  • Se ve personalizado. ¿Cómo se puede determinar cuál debe ser descartada? a o b? Escribir una función personalizada para introducir esta lógica.
  • En primer lugar, ordenar la matriz por el nombre de la ciudad, luego iterar a través de ellos uno por uno eliminación de duplicados como puedo encontrarlos. Si usted no ordenar en primer lugar, tendrás que recorrer toda la matriz para cada entrada de la matriz.
  • Me gustaría utilizar los nombres de las ciudades como las propiedades de un objeto.
  • Un ‘set’ puede ayudarle a: stackoverflow.com/questions/7958292/…
InformationsquelleAutor theblueone | 2013-09-12

11 Comentarios

  1. 47

    Me gustaría probable que el uso de las banderas objeto durante el filtrado, como este:

    var flags = {};
    var newPlaces = places.filter(function(entry) {
        if (flags[entry.city]) {
            return false;
        }
        flags[entry.city] = true;
        return true;
    });

    Que utiliza Array#filtro de ECMAScript5 (ES5), que es uno de los ES5 adiciones que puede ser acuñada (de la búsqueda para «es5 calza» para varias opciones).

    Se puede hacer sin filter, por supuesto, es sólo un poco más detallado:

    var flags = {};
    var newPlaces = [];
    var index;
    for (index = 0; index < places.length; ++index) {
        if (!flags[entry.city]) {
            flags[entry.city] = true;
            newPlaces.push(entry);
        }
    });

    Tanto de los anteriores asumen que el primera objeto con una determinada ciudad debe ser mantenido, y todos los demás se descartan.


    Nota: Como user2736012 señala a continuación, mi prueba if (flags[entry.city]) será cierto para las ciudades con nombres que pasan a ser las mismas que las propiedades que existen en Object.prototype como toString. Muy raro en este caso, pero hay cuatro maneras de evitar la posibilidad de:

    • (Mi costumbre solución preferida) Crear el objeto sin un prototipo: var flags = Object.create(null);. Esta es una característica de ES5. Tenga en cuenta que esto no puede ser acuñada para navegadores obsoletos como IE8 (el único argumento de la versión de Object.create puede ser excepto cuando ese argumento de que el valor de null).

    • Uso hasOwnProperty para la prueba, por ejemplo, if (flags.hasOwnProperty(entry.city))

    • Poner un prefijo que usted sabe que no existe para cualquier Object.prototype de la propiedad, tales como xx:

      var key = "xx" + entry.city;
      if (flags[key]) {
          //...
      }
      flags[key] = true;
    • Como de ES2015, usted podría usar un Set lugar:

      const flags = new Set();
      const newPlaces = places.filter(entry => {
          if (flags.has(entry.city)) {
              return false;
          }
          flags.add(entry.city);
          return true;
      });
    • Mientras que es muy poco probable que habrá una ciudad llamada «toString» o cualquier otro Object.prototype propiedad, todavía no es una mala idea utilizar .hasOwnProperty() para esto.
    • Sí, es un poco paranoico. He de admitir que, sin duda, para este caso. Hace más seguro genérico solución, aunque.
    • Sí, pero creo que para un usuario es que si se generaliza esto, es posible. No me sorprendería encontrar un caso donde alguien generalizado de la técnica y consiguió poco por el constructor de la propiedad, por ejemplo. Él/ella hizo un muy buen punto.
    • muy poco probable que habrá una ciudad llamada «toString» o cualquier otro Objeto.prototipo de la propiedad…»
    • Lo siento, me perdí la broma. He estado pensando acerca de la política de hoy, que me pone de mal humor! 😉
    • Muy útil, gracias 🙂
    • Con el nuevo Conjunto de la clase en Javascript, puede reemplazar las banderas objeto con un nuevo Set() y el uso de banderas.ha(clave) y banderas.agregar(tecla). Entonces usted no necesita preocuparse acerca de colisiones con el objeto prototipo de propiedades.
    • Mejor respuesta: casi todas las otras soluciones que operan en O(n^2) tiempo o algo por el estilo. @Robert Byrne la solución es la siguiente mejor con O(2*n). Este es casi lo mismo que O(n).

  2. 30

    Menor, pero no mejor rendimiento (vea la actualización de abajo) solución para es6 :

    function unique(array, propertyName) {
       return array.filter((e, i) => array.findIndex(a => a[propertyName] === e[propertyName]) === i);
    }

    rendimiento: https://jsperf.com/compare-unique-array-by-property

    • Actualización de 19.08.2018: En Chrome 67.0.3396 / Mac OS X 10.13.6 obtuvo un mejor rendimiento puntuación de 2 otras variantes que se proponen aquí. Comprobar el funcionamiento en los navegadores de destino antes de su uso.
    • estás increíblemente genial!
  3. 4

    https://lodash.com/docs#uniqBy

    https://github.com/lodash/lodash/blob/4.13.1/lodash.js#L7711

    /**
     * This method is like `_.uniq` except that it accepts `iteratee` which is
     * invoked for each element in `array` to generate the criterion by which
     * uniqueness is computed. The iteratee is invoked with one argument: (value).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @param {Array|Function|Object|string} [iteratee=_.identity]
     *  The iteratee invoked per element.
     * @returns {Array} Returns the new duplicate free array.
     * @example
     *
     * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
     * //=> [2.1, 1.2]
     *
     * //The `_.property` iteratee shorthand.
     * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
     * //=> [{ 'x': 1 }, { 'x': 2 }]
     */
  4. 4

    He ampliado un poco en @IgorL solución, sino que se extendió prototipo y le dio un selector de función en lugar de una propiedad para que sea un poco más flexible:

    Array.prototype.unique = function(selector) {
       return this.filter((e, i) => this.findIndex((a) => {
          if (selector) {
            return selector(a) === selector(e);
          }
          return a === e;
        }) === i);
    };

    Uso:

    //with no param it uses strict equals (===) against the object
    let primArr = ['one','one','two','three','one']
    primArr.unique() //['one','two','three']
    
    let a = {foo:123}
    let b = {foo:123}
    let fooArr = [a,a,b]
    fooArr.unique() //[a,b]
    
    //alternatively, you can pass a selector function
    fooArr.unique(item=>item.foo) //[{foo:123}] (first "unique" item returned)

    Definitivamente NO es la más eficiente manera de hacer esto, pero siempre que el selector es simple y la matriz no es masivo, se debe trabajar muy bien.

    En El Manuscrito

    Array.prototype.unique = function<T>(this: T[], selector?: (item: T) => object): T[] {
       return this.filter((e, i) => this.findIndex((a) => {
          if (selector) {
            return selector(a) === selector(e);
          }
          return a === e;
        }) === i);
    };
    • Gracias por este. Funcionó a la perfección, en mi caso de uso!
    • Esta es la mejor solución! Si alguien pudiera proporcionar la más eficiente manera, entonces no sería fantástico. Pero en estas situaciones haciendo una extensión para el prototipo es el camino correcto a seguir, y lo que es el uso de un selector es también la manera correcta de ir (estoy usando manuscrito)
    • Estoy usando el manuscrito demasiado. He añadido la versión mecanografiada de abajo
  5. 3

    Mi sugerencia :

    Array.prototype.uniqueCity = function() {
        var processed = [];
        for (var i=this.length-1; i>=0; i--){
            if (processed.indexOf(this[i].city)<0) {
                processed.push(this[i].city);
            } else {
                this.splice(i, 1);
            }
        }
    }

    de uso :

    places.uniqueCity();

    o

    Array.prototype.uniqueObjectArray = function(field) {
        var processed = [];
        for (var i=this.length-1; i>=0; i--) {
            if (this[i].hasOwnProperty(field)) {
                if (processed.indexOf(this[i][field])<0) {
                    processed.push(this[i][field]);
                } else {
                    this.splice(i, 1);
                }
            }
        }
    }
    
    places.uniqueObjectArray('city');

    Con el anterior, puede ordenar la matriz por cualquiera de los campos en los objetos, incluso si no están presentes para algunos de los objetos.

    o

    function uniqueCity(array) {
        var processed = [];
        for (var i=array.length-1; i>=0; i--){
            if (processed.indexOf(array[i].city)<0) {
                processed.push(array[i].city);
            } else {
                array.splice(i, 1);
            }
        }
        return array;
    }
    
    places = uniqueCity(places);
    • Uno no simplemente jugar con un prototype acaba de agregar esa función específica.
    • «jugar con el prototipo»? Esta es la forma en que javascript está destinado a ser …
    • Estoy de acuerdo con @JakubMichálek. No es que sea malo, pero parece un poco demasiado específicas para un .prototype método. No es un problema técnico, más conceptual, que es subjetivo.
    • Si se puede hacer es general, como prototype.unique y añadir un poco de apoyo a decir para especificar la clave como function(key) { ... }, entonces creo que estaría bien, pero esto me parece poco tonto para mí.
    • No importa extender prototipo cuando @theblueone será perfectamente consciente de que hos propio código, en ese proyecto en particular. No sería una buena idea si usted ha hecho algunos de código abierto de la biblioteca destinados a ser utilizados amplio o en cualquier lugar. entonces usted debe pensar dos veces.
    • Otro problema con este es que opera en O(n^2) tiempo. .indexOf() también recorrer todo el procesado de la matriz, y el procesado de la matriz que se utiliza .indexOf() en es probable que crezca a ser aproximadamente de la misma longitud que la de la matriz original por el tiempo que usted está hecho. Esta es la forma de terminar con casi O(n^2) tiempo en el peor de los casos (que es cuando no hay duplicados). En el mejor de los casos (todos los duplicados) obtendrá O(n) tiempo. La aceptación de respuesta, que utiliza una tabla de búsqueda, siempre cerca de O(n) tiempo.

  6. 2

    Podría usar un Mapa para las entradas con la misma llave de la propiedad (en el caso de ‘la ciudad’) sólo aparecen una vez

    module.exports = (array, prop) => {
       const keyValueArray = array.map(entry => [entry[prop], entry]);
       const map = new Map(keyValueArray);
       return Array.from(map.values());
    };

    Más información sobre el Mapa y los objetos de la matriz aquí

    Ejemplo básico en Codepen

  7. 1

    Como se señaló en los comentarios, se podría utilizar un objeto como un mapa, el cual le permitirá evitar duplicados, puede, a continuación, enumerar las propiedades del objeto.

    de trabajo violín: http://jsfiddle.net/gPRPQ/1/

    var places = [];
    var a = {};
    a.lat = 12.123;
    a.lng = 13.213;
    a.city = "New York";
    
    places.push(a);
    
    var b = {};
    b.lat = 3.123;
    b.lng = 2.213;
    b.city = "New York";
    
    places.push(b);
    
    var unique = {}
    
    for (var i = 0; i < places.length; i++) {
        var place = places[i];
        unique[place.city] = place;
    }
    
    for (var name in unique) {
        var place = unique[name];
        console.log(place);
    }
  8. 1
    var places = [];
    var a = {};
    a.lat = 12.123;
    a.lng = 13.213;
    a.city = "New York";
    
    places.push(a);
    
    var b = {};
    b.lat = 3.123;
    b.lng = 2.213;
    b.city = "New York";
    
    places.push(b);
    
    getUniqAR(places,'city'); //Return Uniq Array by property
    
    function getUniqAR(Data,filter){
    var uniar =[];
    Data.forEach(function(item,ind,arr){
        var dupi=false;
        if(!uniar.length) uniar.push(item) //push first obj into uniq array 
        uniar.forEach(function(item2, ind2,arr){
        if(item2[filter] == item[filter]){  //check each obj prop of uniq array 
          dupi=true; //if values are same put duplicate is true
            }     
        })
    if(!dupi){  uniar.push(item)} //if no duplicate insert to uniq
    
    })
    console.log(uniar)
    return uniar;
    }
  9. 1

    Otra opción:

    const uniqueBy = prop => list => {
        const uniques = {}
        return list.reduce(
            (result, item) => {
                if (uniques[item[prop]]) return result
                uniques[item[prop]] = item
                return [...result, item]
            },
            [],
        )
    }
    
    const uniqueById = uniqueBy('id')
    
    uniqueById([
        { id: 1, name: 'one' },
        { id: 2, name: 'two' },
        { id: 1, name: 'one' },
        { id: 3, name: 'three' }
    ])

    Puedes pegarlo en tu consola para ver su funcionamiento.
    Se debe trabajar para el escenario presentado y algunos otros.

  10. 0

    Simples Javascript código para eliminar duplicados en las ciudades de places lista de matriz es

    var places = [{ 'lat': 12.123, 'lng': 13.213, 'city': "New York"},
                    { 'lat': 3.123, 'lng': 2.213, 'city': "New York"},
                    { 'lat': 43.123, 'lng': 12.213, 'city': "London"}];
    var unique = [];
    var tempArr = [];
    places.forEach((value, index) => {
        if (unique.indexOf(value.city) === -1) {
            unique.push(value.city);
        } else {
            tempArr.push(index);    
        }
    });
    tempArr.reverse();
    tempArr.forEach(ele => {
        places.splice(ele, 1);
    });
    console.log(places);
  11. -1

    Este hilo puede ser viejo, pero pensé que debía compartirlo. Está basado en JavaScript Puro y elimina los Duplicados de los Objetos basándose en las Propiedades Especificadas.

    function removeDuplicates(originalArray, properties) {
      var newArray = [];
      var index = 0;
      var lookupObject = {};
      var totalProperties = properties.length;
    
      for (var i = 0; i < originalArray.length; i++) {
        var exists = false;
    
        for (var a = 0; a < newArray.length; a++) {
          var propsFound = 0;
          for (var b = 0; b < totalProperties; b++) {
            if (originalArray[i][properties[b]] == newArray[a][properties[b]]) {
              propsFound++;
            }
          }
    
          //If there is a match then break the for loop
          if (propsFound == totalProperties) {
            exists = true;
            break;
          }
        } //End of New Array
    
        if (!exists) {
          newArray[index] = originalArray[i];
          index++;
        }
      } //End of originalArray
    
      return newArray;
    }

    Puede ver el violín aquí

Dejar respuesta

Please enter your comment!
Please enter your name here