#javascript #arrays #data-structures #duplicates #frontend
Вопрос:
Я ожидаю универсального решения, включающего объекты более высокого порядка в качестве элемента массива.
const input1 = [1,2,4,6,'4','1',{a:1},{a:1}]; //my code works
const input2 = [1,2,4,6,'4','1',{a:undefined},{b:undefined}]; //my code fails.
function deDuplicate(arr) {
let obj = {};
arr.forEach(value => {
if (!obj[JSON.stringify(value) typeof value]) obj[JSON.stringify(value) typeof value] = value;
});
return Object.values(obj);
}
console.log(deDuplicate(input2));
Комментарии:
1.
JSON.stringify()
удаляет ключи сundefined
function
и другими недопустимыми значениями в строке JSON.JSON.stringify({ a:undefined })
это «{}»`2. Я знаю. Если я удалю JSON.stringify(), то я не смогу удалить дубликаты объектов из массива.
3. Вы можете использовать
JSON.stringify(Object.entries(value))
для объектов, если вас не беспокоит порядок ключей в объекте или то, что null и undefined рассматриваются как одинаковые.4. Смотрите здесь: levelup.gitconnected.com/…
Ответ №1:
включить lodash https://cdnjs.com/libraries/lodash.js или https://www.jsdelivr.com/package/npm/lodash
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
const input1 = [1,2,4,6,'4','1',{a:1},{a:1}]; //my code works
const input2 = [1,2,4,6,'4','1',{a:undefined},{b:undefined}]; //my code fails.
function deDuplicate(arr) {
let res = []
for(const el of arr) {
const dublicateIndex = res.findIndex( (el2) => {
// if both nulls
if( _.isNull(el) amp;amp; _.isNull(el2) ) {
return true
}
// if both undefined
if( _.isUndefined(el) amp;amp; _.isUndefined(el2) ) {
return true
}
// check both are string, or numbers
if(
( _.isNumber(el) || _.isString(el)) amp;amp;
( _.isNumber(el2) || _.isString(el2) )
) {
return el.toString() === el2.toString()
}
// check if one is object, other not
if(_.isObject(el) !== _.isObject(el2)) {
return false
}
// check both is object
if(_.isObject(el) === _.isObject(el2)) {
return _.isEqual(el, el2)
}
return _.isEqual(el, el2)
})
if(dublicateIndex === -1) {
res.push(el)
}
}
return res
}
console.log(deDuplicate(input3));
input1
— [ 1, 2, 4, 6, { a: 1 } ]
input2
— [ 1, 2, 4, 6, { a: undefined }, { b: undefined } ]
живой пример https://jsfiddle.net/9cx4kget/
Комментарии:
1. можете ли вы предоставить ссылку CDN для добавления loadash в мой html?
2. обновленный ответ. Пример jsfiddle.net/knrm7q2f
3. @SupritBeck этот код терпит неудачу, если у вас
undefined
илиnull
в вашем массиве: [1,2,4,6,true,’4′,’1′,’hello’,’hello’,null,undefined,{a:undefined},{b:{a:undefined}},{b:{a:undefined}}]4. @AlanTishin
instanceof
проверяет прототип значения, поэтому, если объект был создан с помощьюObject.create(null)
— это вернетfalse
, проверьте мой ответ о том, как проверить, является ли значениеObject
Ответ №2:
Ванильный раствор
const input2 = [
1,2,4,6,
true,
'4','1',
'hello','hello',
null,
undefined,
{a:undefined},
{b:{a:undefined,b:'hello'}},
{b:{b:'hello',a:undefined}}
];
const unduplicatedInput2 = new Set(input2.map(value => {
const isString = "string" === typeof value;
if(isString) {
const nValue = Number(value);
const isNumber = nValue || 0 === nValue;
if(isNumber) {
return nValue;
}
}
return value;
}));
console.log(unduplicatedInput2);
const isObject = (o) => null !== o amp;amp; 'object' === typeof o;
const sortObjectKeys = (obj) => {
const entries = Object.entries(obj);
const sortedEntries =
entries.sort(([a], [b]) => (a > b) - (a < b));
const deepSort = sortedEntries
.map(([key, value]) => {
if (isObject(value)) {
return [key, sortObjectKeys(value)];
}
return [key, value];
});
return Object.fromEntries(deepSort);
}
const duplicateObjectRemoval = (array) => {
const extractedObjects = array
.filter(a => isObject(a));
const arrayWithNoObjects = array
.filter(a => !isObject(a));
const replacer = (key, value) =>
'undefined' === typeof value ? null : value;
const sortedExtractedObjects =
extractedObjects.map(o => sortObjectKeys(o));
const uniqueObjects = [...new Set(
sortedExtractedObjects.map(o => JSON.stringify(o, replacer))
)].map(s => JSON.parse(s));
return [...arrayWithNoObjects, ...uniqueObjects];
}
console.log(duplicateObjectRemoval([...unduplicatedInput2]));
/*
[
1,
2,
4,
6,
true,
"hello",
null,
undefined,
{
"a": null
},
{
"b": {
"a": null,
"b": "hello"
}
}
]
*/
Комментарии:
1. Можете ли вы показать, как
Set
будет выглядеть подход с помощью?2. Конечно, какие данные могут находиться внутри вашего массива? Объекты, строки, числа, строковые числа и что еще?
3. Для всех типов данных. не забывайте о логических значениях.
4. @SupritBeck Просто откройте консоль и нажмите
Run code snippet
5. в случаях объектов это решение зависит от порядка ключей объектов. Пример
[{b:{b: undefined, a:undefined}}, {b:{a:undefined, b: undefined}}];
не будет дедуплицирован