私はJSを学んでいます。以下のオブジェクトの配列があると仮定します:
var family = [
{
name: "Mike",
age: 10
},
{
name: "Matt"
age: 13
},
{
name: "Nancy",
age: 15
},
{
name: "Adam",
age: 22
},
{
name: "Jenny",
age: 85
},
{
name: "Nancy",
age: 2
},
{
name: "Carl",
age: 40
}
];
Nancyが2回表示されることに注意してください(年齢のみが変更されます)。一意の名前のみを出力するとします。上記のオブジェクトの配列を重複せずに出力するにはどうすればよいですか? ES6がを歓迎します
関連(オブジェクトの使用に適した方法が見つかりませんでした):
[〜#〜] edit [〜#〜]これが私が試したものです。それは文字列でうまく機能しますが、オブジェクトでそれを動作させる方法はわかりません:
family.reduce((a, b) => {
if (a.indexOf(b) < 0 ) {
a.Push(b);
}
return a;
},[]);
Set
を Array#map
および スプレッド演算子...
と組み合わせて使用できます単線。
Mapはすべての名前を持つ配列を返します。これらの名前はセット初期化子に入り、セットのすべての値が配列で返されます。
var family = [{ name: "Mike", age: 10 }, { name: "Matt", age: 13 }, { name: "Nancy", age: 15 }, { name: "Adam", age: 22 }, { name: "Jenny", age: 85 }, { name: "Nancy", age: 2 }, { name: "Carl", age: 40 }],
unique = [...new Set(family.map(a => a.name))];
console.log(unique);
フィルタリングして一意の名前のみを返すには、- Array#filter
と Set
を使用できます。
var family = [{ name: "Mike", age: 10 }, { name: "Matt", age: 13 }, { name: "Nancy", age: 15 }, { name: "Adam", age: 22 }, { name: "Jenny", age: 85 }, { name: "Nancy", age: 2 }, { name: "Carl", age: 40 }],
unique = family.filter((set => f => !set.has(f.name) && set.add(f.name))(new Set));
console.log(unique);
ループの外部のname
の出現をオブジェクトに保存し、以前に出現した場合はフィルターします。
https://jsfiddle.net/nputptbb/2/
_var occurrences = {}
var filteredFamily = family.filter(function(x) {
if (occurrences[x.name]) {
return false;
}
occurrences[x.name] = true;
return true;
})
_
このソリューションを関数に一般化することもできます
_function filterByProperty(array, propertyName) {
var occurrences = {}
return array.filter(function(x) {
var property = x[propertyName]
if (occurrences[property]) {
return false;
}
occurrences[property]] = true;
return true;
})
}
_
そしてそれを次のように使用します
_var filteredFamily = filterByProperty(family, 'name')
_
オブジェクト間で_===
_演算子のみを使用するindexOf
を使用してオブジェクトを比較しないでください。現在の答えが機能しない理由は、JSの_===
_はオブジェクトを深く比較するのではなく、参照を比較するためです。つまり、次のコードを見るとわかります。
_var a = { x: 1 }
var b = { x: 1 }
console.log(a === b) // false
console.log(a === a) // true
_
同じexactオブジェクトが見つかった場合、Equalityは通知しますが、同じ内容のオブジェクトが見つかった場合は通知しません。
この場合、name
上のオブジェクトは一意のキーである必要があるため、比較できます。したがって、_obj.name === obj.name
_の代わりに_obj === obj
_です。さらに、その機能ではなくランタイムに影響するコードの別の問題は、indexOf
の内部でreduce
を使用することです。 indexOf
はO(n)
です。これにより、アルゴリズムの複雑さがO(n^2)
になります。したがって、O(1)
ルックアップを持つオブジェクトを使用することをお勧めします。
これは正常に機能します。
const result = [1, 2, 2, 3, 3, 3, 3].reduce((x, y) => x.includes(y) ? x : [...x, y], []);
console.log(result);
Lodashユーザーのための2つの簡単な方法を考えました
この配列を指定すると:
let family = [
{
name: "Mike",
age: 10
},
{
name: "Matt",
age: 13
},
{
name: "Nancy",
age: 15
},
{
name: "Adam",
age: 22
},
{
name: "Jenny",
age: 85
},
{
name: "Nancy",
age: 2
},
{
name: "Carl",
age: 40
}
]
1。重複を見つける:
let duplicatesArr = _.difference(family, _.uniqBy(family, 'name'), 'name')
// duplicatesArr:
// [{
// name: "Nancy",
// age: 2
// }]
2検証のために、重複があるかどうかを検索します:
let uniqArr = _.uniqBy(family, 'name')
if (uniqArr.length === family.length) {
// No duplicates
}
if (uniqArr.length !== family.length) {
// Has duplicates
}
あなたが言及したコードで、あなたは試すことができます:
_family.filter((item, index, array) => {
return array.map((mapItem) => mapItem['name']).indexOf(item['name']) === index
})
_
または、他のオブジェクトの配列に対しても機能させる汎用関数を使用できます。
_function printUniqueResults (arrayOfObj, key) {
return arrayOfObj.filter((item, index, array) => {
return array.map((mapItem) => mapItem[key]).indexOf(item[key]) === index
})
}
_
そして、printUniqueResults(family, 'name')
を使用します
私はおそらく何らかのオブジェクトをセットアップするでしょう。 ECMAScript 6と言ったので、Set
にアクセスできますが、オブジェクトの値を比較したいので、それよりも少し手間がかかります。
例は次のようになります(わかりやすくするために名前空間のパターンを削除しました)。
var setOfValues = new Set();
var items = [];
function add(item, valueGetter) {
var value = valueGetter(item);
if (setOfValues.has(value))
return;
setOfValues.add(value);
items.Push(item);
}
function addMany(items, valueGetter) {
items.forEach(item => add(item, valueGetter));
}
次のように使用します。
var family = [
...
];
addMany(family, item => item.name);
// items will now contain the unique items
説明:追加された各オブジェクトから値を取得し、取得した値に基づいて、既に追加されているかどうかを判断する必要があります。値ゲッターが必要です。これはアイテムを指定する関数であり、値(item => item.name
)。次に、値がまだ表示されていないアイテムのみを追加します。
クラスの実装:
// Prevents duplicate objects from being added
class ObjectSet {
constructor(key) {
this.key = key;
this.items = [];
this.set = new Set();
}
add(item) {
if (this.set.has(item[this.key])) return;
this.set.add(item[this.key]);
this.items.Push(item);
}
addMany(items) {
items.forEach(item => this.add(item));
}
}
var mySet = new ObjectSet('name');
mySet.addMany(family);
console.log(mySet.items);