javascript - איך להסיר את כל הכפילויות ממערך של אובייקטים?
יש לי אובייקט שמכיל מערך של אובייקטים.
obj = {};
obj.arr = new Array();
obj.arr.push({place:"here",name:"stuff"});
obj.arr.push({place:"there",name:"morestuff"});
obj.arr.push({place:"there",name:"morestuff"});
אני תוהה מה היא השיטה הטובה ביותר להסרת אובייקטים כפולים ממערך. כך לדוגמה, obj.arr יהפוך ל...
{place:"here",name:"stuff"},
{place:"there",name:"morestuff"}
תשובה #1
מה לגבי קצת קסם של ES6?
obj.arr = obj.arr.filter((value, index, self) =>
index === self.findIndex((t) => (
t.place === value.place && t.name === value.name
))
)
כתובת URL לתייחסות
פתרון כללי יותר יהיה:
const uniqueArray = obj.arr.filter((value, index) => {
const _value = JSON.stringify(value);
return index === obj.arr.findIndex(obj => {
return JSON.stringify(obj) === _value;
});
});
שימוש באסטרטגיית התכונה שלמעלה במקום JSON.stringify:
const isPropValuesEqual = (subject, target, propNames) =>
propNames.every(propName => subject[propName] === target[propName]);
const getUniqueItemsByProperties = (items, propNames) =>
items.filter((item, index, array) =>
index === array.findIndex(foundItem => isPropValuesEqual(foundItem, item, propNames))
);
אתה יכול להוסיף עטיפה אם אתה רוצה שתכונת propNames תהיה או מערך או ערך:
const getUniqueItemsByProperties = (items, propNames) => {
const propNamesArray = Array.from(propNames);
return items.filter((item, index, array) =>
index === array.findIndex(foundItem => isPropValuesEqual(foundItem, item, propNamesArray))
);
};
מאפשר גם getUniqueItemsByProperties('a') וגם getUniqueItemsByProperties(['a']);
דוגמת סטאקבליץ'
הסבר
התחל על ידי הבנת שתי השיטות שבהן משתמשים:
- מסנן, findIndex
תשובה #2
שורות בודדות עם filter() (שומר על סדר)
אם יש לך מזהה כלשהו באובייקטים שמסמן ייחודיות (למשל id), אז אנחנו יכולים להשתמש ב-filter() יחד עם findIndex() כדי לעבור דרך הרשימה ולוודא ש-האינדקס של כל אובייקט עם הערך הזה של id תואם רק לעצמו. זאת אומרת שיש רק אובייקט אחד כזה ברשימה, כלומר אין כפילויות.
myArr.filter((obj1, i, arr) =>
arr.findIndex(obj2 => (obj2.id === obj1.id)) === i
)
(שימו לב שהפתרון הזה שומר על המופע הראשון של הכפילויות שנמצאו בתוצאה. ניתן במקום זאת לקחת את המופע האחרון על ידי החלפת findIndex ב-findLastIndex בדוגמה שלמעלה.)
אם הסדר אינו חשוב, אז פתרונות עם מפתחות יהיו מהירים יותר: פתרון עם מפת
הפורמט שלמעלה יכול להיות מיושם על מקרים אחרים על ידי שינוי האופן שבו אנחנו בודקים שכפולים (למשל, החלפת obj2.id === obj1.id במשהו אחר).
ייחודי על פי תכונות מרובות (למשל place ו-name, כפי שבשאלה)
myArr.filter((obj1, i, arr) =>
arr.findIndex(obj2 =>
['place', 'name'].every(key => obj2[key] === obj1[key])
) === i
)
יחיד בכל התכונות
myArr.filter((obj1, i, arr) =>
arr.findIndex(obj2 =>
JSON.stringify(obj2) === JSON.stringify(obj1)
) === i
)
הערות אזהרה:
- זה עלול להאט, בהתאם לגודל האובייקטים והמטריצות
סדר המפתחות ב-
JSON.stringify()הוא בדרך כלל עקבי, אך מובטח רק ב-ES2015 ומאוחר יותר- זה אומר שהמרחק שתעבור יכול להשתנות, וייתכן שתרצה להעדיף משהו עמיד יותר (כמו השוואת מפתחות ספציפיים)
תשובה #3
באמצעות ES6+ בשורה אחת ניתן לקבל רשימה ייחודית של אובייקטים לפי מפתח:
const key = 'place';
const unique = [...new Map(arr.map(item => [item[key], item])).values()]
ניתן לשים זאת בפונקציה:
function getUniqueListBy(arr, key) {
return [...new Map(arr.map(item => [item[key], item])).values()]
}
הנה דוגמה עובדת:
const arr = [
{place: "here", name: "x", other: "other stuff1" },
{place: "there", name: "x", other: "other stuff2" },
{place: "here", name: "y", other: "other stuff4" },
{place: "here", name: "z", other: "other stuff5" }
]
function getUniqueListBy(arr, key) {
return [...new Map(arr.map(item => [item[key], item])).values()]
}
const arr1 = getUniqueListBy(arr, 'place')
console.log("Unique by place")
console.log(JSON.stringify(arr1))
console.log("\nUnique by name")
const arr2 = getUniqueListBy(arr, 'name')
console.log(JSON.stringify(arr2))איך זה עובד
ראשית, המערך ממופה מחדש בצורה כך שהוא יכול לשמש כקלט עבור מפה.
arr.map(item => [item[key], item]);
זאת אומרת שכל פריט במערך יומר למערך אחר עם 2 אלמנטים; ה-מפתח הנבחר כאלמנט הראשון ו-כל הפריט המקורי כאלמנט השני, זה נקרא רשומה (לדוגמה: רשומות של מערכים, רשומות של Map). וכאן היא התיעוד הרשמי עם דוגמה שמראה איך להוסיף רשומות של מערך בבנאי של Map.
דוגמה כאשר המפתח הוא place:
[["here", {place: "here", name: "x", other: "other stuff1" }], ...]
שנית, אנו מעבירים את המערך המותאם הזה לבנאי של Map וכאן הקסם מתרחש. Map יסיר את ערכי המפתחות הכפולים, וישמור רק על הערך האחרון שהוכנס עבור אותו מפתח. הערה: Map שומרת על סדר ההכנסה. (בדוק את ההבדל בין Map לאובייקט)
מפה חדשה (מערך הערכים שהומר זה עתה למפה)
שלישית, אנו משתמשים בערכי המפה כדי להשיג את הפריטים המקוריים, אך הפעם ללא כפילויות.
ערך חדש של Map(mappedArr)
והאחרון הוא להוסיף את הערכים האלה למערך חדש ורענן כך שהוא יוכל להיראות כמו המבנה הראשוני ולהחזיר זאת:
להחזיר [...new Map(mappedArr).values()]
תשובה #4
פתרון פשוט ובעל ביצועים טובים יותר בזמן ריצה מאשר 70+ התשובות שכבר קיימות:
const ids = arr.map(({ id }) => id);
const filtered = arr.filter(({ id }, index) => !ids.includes(id, index + 1));
דוגמה :
const arr = [{
id: 1,
name: 'one'
}, {
id: 2,
name: 'two'
}, {
id: 1,
name: 'one'
}];
const ids = arr.map(({ id }) => id);
const filtered = arr.filter(({ id }, index) => !ids.includes(id, index + 1));
console.log(filtered);איך זה עובד:
Array.filter() מוסיף להסיר את כל האובייקטים הכפולים על ידי בדיקה אם המערך של המזהים שמופים בעבר מכיל את המזהה הנוכחי ({id} מפרק את האובייקט רק למזהה שלו). כדי לסנן רק כפילויות אמיתיות, הוא משתמש בפרמטר השני fromIndex של Array.includes() עם index + 1 שיתעלם מהאובייקט הנוכחי ומהאובייקטים הקודמים.
מאז שכל איטרציה של שיטת ה-filter תבדוק את המערך רק החל מהאינדקס הנוכחי + 1, זה גם מפחית בצורה דרמטית את זמן הריצה כי רק אובייקטים שלא סוננו קודם נבדקים.
מה אם אין לך מזהה ייחודי אחד כמו id?
פשוט צור אחד זמני:
const objToId = ({ name, city, birthyear }) => `${name}-${city}-${birthyear}`;
const ids = arr.map(objToId);
const filtered = arr.filter((item, index) => !ids.includes(objToId(item), index + 1));
תשובה #5
שיטה פרימיטיבית תהיה:
const obj = {};
for (let i = 0, len = things.thing.length; i < len; i++) {
obj[things.thing[i]['place']] = things.thing[i];
}
things.thing = new Array();
for (const key in obj) {
things.thing.push(obj[key]);
}
תשובה #6
אם אתה יכול להשתמש בספריות Javascript כמו underscore או lodash, אני ממליץ להסתכל על הפונקציה _.uniq בספריות שלהם. מתוך lodash:
_.uniq(array, [isSorted=false], [callback=_.identity], [thisArg])
בבסיס, אתה מעביר את המערך שכאן הוא אובייקט ליטרלי ואתה מעביר את התכונה שאתה רוצה להסיר כפילויות לפי היא במערך הנתונים המקורי, כך:
var data = [{'name': 'Amir', 'surname': 'Rahnama'}, {'name': 'Amir', 'surname': 'Stevens'}];
var non_duplidated_data = _.uniq(data, 'name');
עדכון: Lodash עכשיו גם הציגה את .uniqBy.
תשובה #7
היה לי את אותו דרישה בדיוק, להסיר אובייקטים חוזרים במערך, בהתבסס על כפילויות בשדה אחד. מצאתי את הקוד כאן: Javascript: הסרת כפילויות ממערך של אובייקטים
אז בדוגמה שלי, אני מסיר כל אובייקט מהמערך שיש לו ערך מחרוזת licenseNum כפול.
var arrayWithDuplicates = [
{"type":"LICENSE", "licenseNum": "12345", state:"NV"},
{"type":"LICENSE", "licenseNum": "A7846", state:"CA"},
{"type":"LICENSE", "licenseNum": "12345", state:"OR"},
{"type":"LICENSE", "licenseNum": "10849", state:"CA"},
{"type":"LICENSE", "licenseNum": "B7037", state:"WA"},
{"type":"LICENSE", "licenseNum": "12345", state:"NM"}
];
function removeDuplicates(originalArray, prop) {
var newArray = [];
var lookupObject = {};
for(var i in originalArray) {
lookupObject[originalArray[i][prop]] = originalArray[i];
}
for(i in lookupObject) {
newArray.push(lookupObject[i]);
}
return newArray;
}
var uniqueArray = removeDuplicates(arrayWithDuplicates, "licenseNum");
console.log("uniqueArray is: " + JSON.stringify(uniqueArray));
התוצאות:
uniqueArray הוא:
[{"type":"LICENSE","licenseNum":"10849","state":"CA"},
{"type":"LICENSE","licenseNum":"12345","state":"NM"},
{"type":"LICENSE","licenseNum":"A7846","state":"CA"},
{"type":"LICENSE","licenseNum":"B7037","state":"WA"}]
תשובה #8
שורה אחת המשתמשת ב-Set
var things = new Object();
things.thing = new Array();
things.thing.push({place:"here",name:"stuff"});
things.thing.push({place:"there",name:"morestuff"});
things.thing.push({place:"there",name:"morestuff"});
// assign things.thing to myData for brevity
var myData = things.thing;
things.thing = Array.from(new Set(myData.map(JSON.stringify))).map(JSON.parse);
console.log(things.thing)הסבר:
new Set(myData.map(JSON.stringify))יוצר אובייקט Set באמצעות האלמנטים של myData שהוסבו למחרוזות.- אובייקט מסוג Set יבטיח שכל אלמנט יהיה ייחודי.
- לאחר מכן אני יוצר מערך המבוסס על האלמנטים של הקבוצה שיצרתי באמצעות Array.from.
- לבסוף, אני משתמש ב-JSON.parse כדי להמיר מחרוזת של אלמנט חזרה לאובייקט.
תשובה #9
שורת קוד אחת ב-ES6 כאן
let arr = [
{id:1,name:"sravan ganji"},
{id:2,name:"pinky"},
{id:4,name:"mammu"},
{id:3,name:"avy"},
{id:3,name:"rashni"},
];
console.log(Object.values(arr.reduce((acc,cur)=>Object.assign(acc,{[cur.id]:cur}),{})))תשובה #10
כדי להסיר את כל הכפילויות ממערך של אובייקטים, הדרך הפשוטה ביותר היא להשתמש ב-filter:
var uniq = {};
var arr = [{"id":"1"},{"id":"1"},{"id":"2"}];
var arrFiltered = arr.filter(obj => !uniq[obj.id] && (uniq[obj.id] = true));
console.log('arrFiltered', arrFiltered);תשובה #11
שורות בודדות עם Map (ביצועים גבוהים, אינו שומר על הסדר)
מצא id ייחודיים במערך arr.
const arrUniq = [...new Map(arr.map(v => [v.id, v])).values()]
אם הסדר חשוב עיינו בפתרון עם מסנן: פתרון עם מסנן
ייחודי לפי מספר תכונות ( place ו-name ) במערך arr
const arrUniq = [...new Map(arr.map(v => [JSON.stringify([v.place,v.name]), v])).values()]
ייחודי בכל התכונות במערך arr
const arrUniq = [...new Map(arr.map(v => [JSON.stringify(v), v])).values()]
השאר את ההופעה הראשונה במערך arr
const arrUniq = [...new Map(arr.slice().reverse().map(v => [v.id, v])).values()].reverse()
תשובה #12
הנה אפשרות נוספת לעשות זאת באמצעות שיטות איטרציה של מערכים אם אתה צריך השוואה רק לפי שדה אחד של אובייקט:
function uniq(a, param){
return a.filter(function(item, pos, array){
return array.map(function(mapItem){ return mapItem[param]; }).indexOf(item[param]) === pos;
})
}
uniq(things.thing, 'place');
תשובה #13
אם אתה יכול לחכות כדי להיפטר מהכפילויות עד אחרי כל ההוספות, הגישה הנפוצה היא קודם למיין את המערך ואז להיפטר מהכפילויות. המיון מונע את הגישה של N * N של סריקת המערך עבור כל אלמנט בזמן שאתה עובר דרכם.
פונקציית "הסרת כפילויות" נקראת בדרך כלל unique או uniq. חלק מהמימושים הקיימים עשויים לשלב את שני הצעדים, לדוגמה, uniq של פרוטוטייפ
פוסט זה מכיל כמה רעיונות לנסות (וכמה להימנע מהם :-) ) אם לספרייה שלך עדיין אין אחד כזה! באופן אישי, אני מוצא את זה הכי ישר קדימה:
function unique(a){
a.sort();
for(var i = 1; i < a.length; ){
if(a[i-1] == a[i]){
a.splice(i, 1);
} else {
i++;
}
}
return a;
}
// Provide your own comparison
function unique(a, compareFunc){
a.sort( compareFunc );
for(var i = 1; i < a.length; ){
if( compareFunc(a[i-1], a[i]) === 0){
a.splice(i, 1);
} else {
i++;
}
}
return a;
}
תשובה #14
זו דרך כללית לעשות זאת: אתה מעביר פונקציה שבודקת האם שני איברים במערך נחשבים שווים. במקרה זה, היא משווה את הערכים של התכונות name ו-place של שני האובייקטים שמושווים.
תשובת ES5
function removeDuplicates(arr, equals) {
var originalArr = arr.slice(0);
var i, len, val;
arr.length = 0;
for (i = 0, len = originalArr.length; i < len; ++i) {
val = originalArr[i];
if (!arr.some(function(item) { return equals(item, val); })) {
arr.push(val);
}
}
}
function thingsEqual(thing1, thing2) {
return thing1.place === thing2.place
&& thing1.name === thing2.name;
}
var things = [
{place:"here",name:"stuff"},
{place:"there",name:"morestuff"},
{place:"there",name:"morestuff"}
];
removeDuplicates(things, thingsEqual);
console.log(things);תשובת ES3 מקורית
function arrayContains(arr, val, equals) {
var i = arr.length;
while (i--) {
if ( equals(arr[i], val) ) {
return true;
}
}
return false;
}
function removeDuplicates(arr, equals) {
var originalArr = arr.slice(0);
var i, len, j, val;
arr.length = 0;
for (i = 0, len = originalArr.length; i < len; ++i) {
val = originalArr[i];
if (!arrayContains(arr, val, equals)) {
arr.push(val);
}
}
}
function thingsEqual(thing1, thing2) {
return thing1.place === thing2.place
&& thing1.name === thing2.name;
}
removeDuplicates(things.thing, thingsEqual);
תשובה #15
אני חושב שהגישה הטובה ביותר היא להשתמש ב-reduce ובאובייקט Map. זו פתרון בשורה אחת.
const data = [
{id: 1, name: 'David'},
{id: 2, name: 'Mark'},
{id: 2, name: 'Lora'},
{id: 4, name: 'Tyler'},
{id: 4, name: 'Donald'},
{id: 5, name: 'Adrian'},
{id: 6, name: 'Michael'}
]
const uniqueData = [...data.reduce((map, obj) => map.set(obj.id, obj), new Map()).values()];
console.log(uniqueData)
/*
in `map.set(obj.id, obj)`
'obj.id' is key. (don't worry. we'll get only values using the .values() method)
'obj' is whole object.
*/תשובה #16
בהתחשב ב-lodash.uniqWith
const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
_.uniqWith(objects, _.isEqual);
// => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
תשובה #17
להוסיף עוד אחד לרשימה. שימוש ב-ES6 ו-Array.reduce עם Array.find.
בדוגמה זו מסננים אובייקטים על בסיס תכונת guid.
let filtered = array.reduce((accumulator, current) => {
if (! accumulator.find(({guid}) => guid === current.guid)) {
accumulator.push(current);
}
return accumulator;
}, []);
הרחבת זה כדי לאפשר בחירת נכס ודחיסתו לשורת קוד אחת:
const uniqify = (array, key) => array.reduce((prev, curr) => prev.find(a => a[key] === curr[key]) ? prev : prev.push(curr) && prev, []);
כדי להשתמש בזה, העבירו מערך של אובייקטים ואת שם המפתח שברצונכם לנקות כפלט של מחרוזת:
const result = uniqify(myArrayOfObjects, 'guid')
תשובה #18
אתה גם יכול להשתמש ב-Map:
const dedupThings = Array.from(things.thing.reduce((m, t) => m.set(t.place, t), new Map()).values());
דוגמה מלאה:
const things = new Object();
things.thing = new Array();
things.thing.push({place:"here",name:"stuff"});
things.thing.push({place:"there",name:"morestuff"});
things.thing.push({place:"there",name:"morestuff"});
const dedupThings = Array.from(things.thing.reduce((m, t) => m.set(t.place, t), new Map()).values());
console.log(JSON.stringify(dedupThings, null, 4));
תוצאה :
[
{
"place": "here",
"name": "stuff"
},
{
"place": "there",
"name": "morestuff"
}
]
תשובה #19
וואו, ילדים, בואו לדעת את זה, למה שלא נעשה את זה?
let uniqIds = {}, source = [{id:'a'},{id:'b'},{id:'c'},{id:'b'},{id:'a'},{id:'d'}];
let filtered = source.filter(obj => !uniqIds[obj.id] && (uniqIds[obj.id] = true));
console.log(filtered);
// EXPECTED: [{id:'a'},{id:'b'},{id:'c'},{id:'d'}];תשובה #20
let myData = [{place:"here",name:"stuff"},
{place:"there",name:"morestuff"},
{place:"there",name:"morestuff"}];
let q = [...new Map(myData.map(obj => [JSON.stringify(obj), obj])).values()];
console.log(q)שורת קוד אחת באמצעות ES6 ו-new Map().
// assign things.thing to myData
let myData = things.thing;
[...new Map(myData.map(obj => [JSON.stringify(obj), obj])).values()];
פרטים:-
- ביצוע
.map()על רשימת הנתונים והפיכת כל אובייקט יחיד למערך[key, value](אורך =2), האלמנט הראשון (key) יהיה הגרסהstringifiedשל האובייקט והאלמנט השני (value) יהיהobjectבעצמו. - הוספת רשימת המערך שנוצרה למעלה ל-
new Map()תגרום לכך שהמפתח יהיה אובייקטstringifiedוכל הוספה של אותו מפתח תגרום להחלפת המפתח הקיים כבר. - שימוש ב-
.values()ייתן MapIterator עם כל הערכים במפה (objבמקרה שלנו) - לבסוף, אופרטור
spread ...כדי ליצור מערך חדש עם הערכים מהשלב הקודם.
תשובה #21
פתרון TypeScript
זה יסיר אובייקטים כפולים וגם ישמור על סוגי האובייקטים.
function removeDuplicateObjects(array: any[]) {
return [...new Set(array.map(s => JSON.stringify(s)))]
.map(s => JSON.parse(s));
}
תשובה #22
const things = [
{place:"here",name:"stuff"},
{place:"there",name:"morestuff"},
{place:"there",name:"morestuff"}
];
const filteredArr = things.reduce((thing, current) => {
const x = thing.find(item => item.place === current.place);
if (!x) {
return thing.concat([current]);
} else {
return thing;
}
}, []);
console.log(filteredArr)פתרון באמצעות אובייקט Set | בהתאם לסוג הנתונים :
const seen = new Set();
const things = [
{place:"here",name:"stuff"},
{place:"there",name:"morestuff"},
{place:"there",name:"morestuff"}
];
const filteredArr = things.filter(el => {
const duplicate = seen.has(el.place);
seen.add(el.place);
return !duplicate;
});
console.log(filteredArr)הגדר תכונת אובייקט :
כל ערך באובייקט Set חייב להיות ייחודי, שוויון הערכים יוּבדק
המטרה של אובייקט Set היא לאחסן ערכים ייחודיים בהתאם לסוג הנתונים, בין אם ערכים פרימיטיביים או הפניות לאובייקטים. יש לו ארבע שיטות מופע מאוד שימושיות: add, clear, has ו-delete.
תכונה ייחודית וסוג הנתונים:..
add שיטה :
זה דוחף נתונים ייחודיים לאוסף כברירת מחדל וגם שומר על סוג הנתון.. זאת אומרת שזה מונע דחיפת פריט כפול לאוסף וגם בודק את סוג הנתון כברירת מחדל...
has שיטה :
לפעמים צריך לבדוק אם פריט נתונים קיים באוסף, וזהו שיטה שימושית לאוסף לבדוק מזהה ייחודי או פריט וסוג נתונים.
delete שיטה :
זה יסיר פריט ספציפי מהאוסף על ידי זיהוי סוג הנתונים.
clear שיטה :
זה יסיר את כל פריטי הקולקציה משתנה מסוים ויקבע אותו כאובייקט ריק
אובייקט Set יש גם שיטות איטרציה ועוד תכונות..
לקרוא טוב יותר מכאן : Set - JavaScript | MDN
תשובה #23
אם המערך מכיל אובייקטים, אז ניתן להשתמש בזה כדי להסיר כפילויות
const persons= [
{ id: 1, name: 'John',phone:'23' },
{ id: 2, name: 'Jane',phone:'23'},
{ id: 1, name: 'Johnny',phone:'56' },
{ id: 4, name: 'Alice',phone:'67' },
];
const unique = [...new Map(persons.map((m) => [m.id, m])).values()];
אם להסיר כפילויות על בסיס הטלפון, פשוט החלף את m.id ב- m.phone
const unique = [...new Map(persons.map((m) => [m.phone, m])).values()];
תשובה #24
removeDuplicates() מקבל מערך של אובייקטים ומחזיר מערך חדש ללא שום אובייקטים כפולים (מבוסס על תכונת id).
const allTests = [
{name: 'Test1', id: '1'},
{name: 'Test3', id: '3'},
{name: 'Test2', id: '2'},
{name: 'Test2', id: '2'},
{name: 'Test3', id: '3'}
];
function removeDuplicates(array) {
let uniq = {};
return array.filter(obj => !uniq[obj.id] && (uniq[obj.id] = true))
}
removeDuplicates(allTests);
תוצאה צפויה:
[
{name: 'Test1', id: '1'},
{name: 'Test3', id: '3'},
{name: 'Test2', id: '2'}
];
ראשית, אנו קובעים את הערך של המשתנה uniq לאובייקט ריק.
לאחר מכן, אנחנו מסננים את המערך של האובייקטים. הסינון יוצר מערך חדש עם כל האלמנטים שעוברים את הבדיקה שמבוצעת על ידי הפונקציה המסופקת.
return array.filter(obj => !uniq[obj.id] && (uniq[obj.id] = true));
מעל, אנו משתמשים בפונקציונליות הקצרה של &&. אם הצד השמאלי של && מעריך כ-true, אז הוא מחזיר את הערך בצד הימני של &&. אם הצד השמאלי הוא false, הוא מחזיר את מה שמופיע בצד השמאלי של &&.
עבור כל אובייקט (obj) אנחנו בודקים ב-uniq אם יש לו מאפיין בשם הערך של obj.id (במקרה הזה, באיטרציה הראשונה הוא יבדוק עבור המאפיין '1'). אנו רוצים את ההפך ממה שהוא מחזיר (אופציה נכונה או לא נכונה) ולכן אנו משתמשים ב-! ב-!uniq[obj.id]. אם ל-uniq כבר יש את המאפיין id, זה יחזיר true שמעריכים אותו ל-false (!) ואומר לפונקציית הסינון NOT להוסיף את ה-obj הזה. לעומת זאת, אם הוא לא מוצא את מאפיין obj.id, זה מחזיר false שמעריכים אותו ל-true (!) ומחזיר את כל מה שמימין ל-&&, כלומר (uniq[obj.id]=true). זהו ערך אמת, שאומר לפונקציית הסינון להוסיף את ה-obj למערך המוחזר, ומוסיף גם את המאפיין {1: true} ל-uniq. זה מבטיח שכל מופע אחר של obj עם אותו id לא יתווסף שוב.
תשובה #25
תשובה מהירה (פחות זמן ריצה) ובטוחה טיפוס עבור מפתחי Typescript עצלנים:
export const uniqueBy = <T>( uniqueKey: keyof T, objects: T[]): T[] => {
const ids = objects.map(object => object[uniqueKey]);
return objects.filter((object, index) => !ids.includes(object[uniqueKey], index + 1));
}
תשובה #26
הדרך הזו עובדת טוב עבורי:
function arrayUnique(arr, uniqueKey) {
const flagList = new Set()
return arr.filter(function(item) {
if (!flagList.has(item[uniqueKey])) {
flagList.add(item[uniqueKey])
return true
}
})
}
const data = [
{
name: 'Kyle',
occupation: 'Fashion Designer'
},
{
name: 'Kyle',
occupation: 'Fashion Designer'
},
{
name: 'Emily',
occupation: 'Web Designer'
},
{
name: 'Melissa',
occupation: 'Fashion Designer'
},
{
name: 'Tom',
occupation: 'Web Developer'
},
{
name: 'Tom',
occupation: 'Web Developer'
}
]
console.table(arrayUnique(data, 'name'))// work well
הדפסה
┌─────────┬───────────┬────────────────────┐
│ (index) │ name │ occupation │
├─────────┼───────────┼────────────────────┤
│ 0 │ 'Kyle' │ 'Fashion Designer' │
│ 1 │ 'Emily' │ 'Web Designer' │
│ 2 │ 'Melissa' │ 'Fashion Designer' │
│ 3 │ 'Tom' │ 'Web Developer' │
└─────────┴───────────┴────────────────────┘
ES5:
function arrayUnique(arr, uniqueKey) {
const flagList = []
return arr.filter(function(item) {
if (flagList.indexOf(item[uniqueKey]) === -1) {
flagList.push(item[uniqueKey])
return true
}
})
}
שתי הדרכים האלה פשוטות ומובנות יותר.
