次のようなオブジェクトの配列を作成しました。
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);
...
同じ都市プロパティを持たないオブジェクトのみを含むように場所をフィルタリングする新しい配列を作成しようとしています(緯度/経度の重複は問題ありません)。これを実現するための組み込みのJSまたはJquery関数はありますか?
フィルタリング中に、おそらく次のようにフラグオブジェクトを使用します。
var flags = {};
var newPlaces = places.filter(function(entry) {
if (flags[entry.city]) {
return false;
}
flags[entry.city] = true;
return true;
});
これは、ECMAScript5(ES5)の Array#filter
を使用します。これは、シムできるES5の追加の1つです(いくつかのオプションについては「es5シム」を検索してください)。
filter
なしでもできます。もちろん、もう少し冗長です。
var flags = {};
var newPlaces = [];
var index;
for (index = 0; index < places.length; ++index) {
if (!flags[entry.city]) {
flags[entry.city] = true;
newPlaces.Push(entry);
}
});
上記の両方は、特定の都市のfirstオブジェクトを保持し、他のすべてを破棄することを前提としています。
注:以下でuser2736012が指摘しているように、私のテストif (flags[entry.city])
は、toString
などのObject.prototype
に存在するプロパティと同じ名前の都市に対して真になります。この場合はほとんどありませんが、可能性を回避する方法は4つあります。
(私の通常の推奨ソリューション)プロトタイプなしでオブジェクトを作成します:var flags = Object.create(null);
。これはES5の機能です。 IE8のような廃止されたブラウザでは、これをシムできないことに注意してください(引数の値がnull
の場合、Object.create
の単一引数バージョンはexceptになります) )。
テストにはhasOwnProperty
を使用します。 if (flags.hasOwnProperty(entry.city))
xx
など、Object.prototype
プロパティに存在しないことがわかっているものにプレフィックスを付けます。
var key = "xx" + entry.city;
if (flags[key]) {
// ...
}
flags[key] = true;
ES2015以降、代わりにSet
を使用できます:
const flags = new Set();
const newPlaces = places.filter(entry => {
if (flags.has(entry.city)) {
return false;
}
flags.add(entry.city);
return true;
});
最短、しかし最高のパフォーマンスではない (以下の更新を参照)es6のソリューション:
function unique(array, propertyName) {
return array.filter((e, i) => array.findIndex(a => a[propertyName] === e[propertyName]) === i);
}
パフォーマンス: https://jsperf.com/compare-unique-array-by-property
@IgorLソリューションを少し拡張しましたが、プロトタイプを拡張し、プロパティの代わりにセレクター関数を与えて、柔軟性を少し高めました。
Array.prototype.unique = function(selector) {
return this.filter((e, i) => this.findIndex((a) => {
if (selector) {
return selector(a) === selector(e);
}
return a === e;
}) === i);
};
使用法:
// 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)
これを行う最も確実な方法ではありませんが、セレクターが単純で配列が大規模でない限り、正常に機能します。
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);
};
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 }]
*/
私のおすすめ :
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);
}
}
}
使用中で :
places.uniqueCity();
または
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');
上記を使用すると、オブジェクト内の任意のフィールドで配列をソートできますオブジェクトの一部に存在しない場合でも。
または
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);
Mapを使用して、同じキープロパティ(この場合は「city」)を持つエントリが1回だけ表示されるようにすることができます
module.exports = (array, prop) => {
const keyValueArray = array.map(entry => [entry[prop], entry]);
const map = new Map(keyValueArray);
return Array.from(map.values());
};
Mapオブジェクトと配列オブジェクトの詳細 here
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;
}
コメントで指摘されているように、オブジェクトをマップとして使用すると、重複を避けることができ、オブジェクトのプロパティを列挙できます。
作業フィドル: 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);
}
別のオプション:
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' }
])
コンソールに貼り付けて、動作を確認できます。提示されたシナリオおよび他のいくつかのシナリオで機能するはずです。
単純なJavascript
コードでは、places
配列リストから重複する都市を削除します
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);