2016-10-06 7 views
2

私はJSを学んでいます。 ナンシーは(唯一の年齢を変更)を2回まで表示されていることをオブジェクトのJavaScript配列で重複する値を見つけて一意の値だけを出力する方法はありますか?

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 
    } 
]; 

は注意してください:私は、オブジェクトの以下の配列を持っていると仮定すると。一意の名前だけを出力したいとします。重複することなく上記のオブジェクト配列を出力するにはどうすればよいですか? ES6はを歓迎します。

関連(オブジェクト上の使用のための良い方法を見つけることができませんでした):

EDITは、ここに私が試したものです。これは、文字列でうまく動作しますが、私はそれがオブジェクトを動作させる方法を見つけ出すことはできません。

family.reduce((a, b) => { 
    if (a.indexOf(b) < 0) { 
    a.push(b); 
    } 
    return a; 
},[]); 
+1

あなたが試したことを投稿できますか? – JordanHendrix

+0

実際に私が言及した両方の関連する質問からほとんどの回答を試みました。 –

+2

誰かがなぜそれらのdownvotesを説明することができますか?ちょうど私が試したと言うためにここで動作しないコードをコピー/貼り付けするべきですか? –

答えて

15

あなたがArray#mapと一行でspread operator...との組み合わせでSetを使用することができます。

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);

のみ一意の名前を返す、あなたはSetArray#filterを使用することができます。あなたが言及したコードで

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);

+0

このフラットアレイの代わりにオブジェクトの配列を出力する方法はありますか? –

+0

あなたの質問はどうですか*ユニークな名前だけを出力したいですか?そうでない場合は、最初のオブジェクトを取得するか、最後のオブジェクトを取得しますか? –

+0

非常にうまくいった。私は徹底的に説明した2つのオプションが好きです。 –

5

オブジェクト内のループ、およびフィルタへの外部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 

平等はあなたを教えてくれますが、同じ内容を持つオブジェクトが見つからない場合。

nameのオブジェクトは、一意のキーである必要があるため、この場合は比較することができます。したがってobj === objではなくobj.name === obj.nameとなります。さらに、実行時に影響を与えるコードのもう1つの問題は、reduceの中にindexOfを使用することです。 indexOfO(n)であり、アルゴリズムの複雑さはO(n^2)になります。したがって、O(1)ルックアップを持つオブジェクトを使用する方が良いです。

+0

downbotesのファンではありません:/ – m0meni

+0

おそらく、あなたのフィドルがコンソールに書き込んでいるので... o/pを見て、何かがうまくいきました...コードを最初にチェックするのが面倒です(そして、コンソールへの書き込みを参照してください) –

+2

私は本当にこの答えに感謝しています - それはクロスブラウザ、パフォーマンス、および読みやすいです。 –

-1

私はおそらく何らかのオブジェクトを設定します。あなたは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 

説明:あなたは、各オブジェクトから値をプルする必要が

の例は、この(明確にするため取り除か名前空間パターン)のようになりますそれが追加され、あなたが得た価値に基づいて、すでに追加されているかどうかを決定します。これは、項目を与えられた関数である値getterを必要とし、値(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); 
+0

これはあまりにも不必要に、あまりにも複雑です – m0meni

+0

@ AR7複合体ですか?私は5分のようにそれを書いた。それは、カプセル化がjavascriptでどのように機能するかという点で、醜いものに見えます。 –

+0

@ AR7不要な名前空間パターンを削除しました –

0

、あなたが試すことができます:

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')

(FIDDLE)

関連する問題