interface FormValues {
    key: string;
    value: any;
}

const array: FormValues[] = [
    {
        key: 'A',
        value: 1 // number
    },
    {
        key: 'A',
        value: 1 // number
    },
    {
        key: 'A',
        value: 'str' // string
    },
    {
        key: 'C',
        value: { a: 1, b: '2' } // object
    },
    {
        key: 'C',
        value: ['a','2'] // array
    },
    {
        key: 'C',
        value: ['a','2'] // array
    }
    {
        key: 'B',
        value: true // boolean
    }
]

Я хочу отфильтровать объекты на основе поля value, которое может иметь значение любого типа.

Я пытался сделать это вот так; мое решение не работает для проверок вложенных объектов.

const key = 'value';
const arrayUniqueByKey = [...new Map(array.map(item => [item[key], item])).values()];

Выход :

    [{
        key: 'A',
        value: 1 // number
    },
    {
        key: 'A',
        value: 'str' // string
    },
    {
        key: 'C',
        value: { a: 1, b: '2' } // object
    },
    {
        key: 'C',
        value: ['a','2'] // array
    },
    {
        key: 'B',
        value: true // boolean
    }]
1
Himanshu Teotia 14 Июн 2021 в 18:29

2 ответа

Лучший ответ

Вам нужно решить, что делает два разных объекта «равными». В JavaScript все встроенные сравнения объектов (включая массивы): по ссылке. Это означает, что ['a','2'] === ['a','2'] равно false, потому что существуют два разных объекта массива, несмотря на то, что они имеют одинаковое содержимое. Подробнее см. Как определить равенство двух объектов JavaScript? Информация.

Я воспользуюсь подходом, согласно которому вы хотели бы, чтобы два значения считались равными, если они сериализуются в одно и то же значение с помощью модифицированной версии JSON.stringify(), где порядок ключей свойств гарантированно будет одинаковым (так что {a: 1, b: 2} и {{X2} } будут равны независимо от того, как они структурированы). Я использую версию из этого ответа для этого:

function JSONstringifyOrder(obj: any, space?: number) {
    var allKeys: string[] = [];
    var seen: Record<string, null | undefined> = {};
    JSON.stringify(obj, function (key, value) {
        if (!(key in seen)) {
            allKeys.push(key); seen[key] = null;
        }
        return value;
    });
    allKeys.sort();
    return JSON.stringify(obj, allKeys, space);
}

И теперь я могу использовать это, чтобы сделать ключи вашего Map:

const arrayUniqueByKey = [...new Map(array.map(
    item => [JSONstringifyOrder(item[key]), item]
)).values()];

И вы можете убедиться, что он ведет себя так, как вам хочется:

console.log(arrayUniqueByKey);
/* [{
  "key": "A",
  "value": 1
}, {
  "key": "A",
  "value": "str"
}, {
  "key": "C",
  "value": {
    "a": 1,
    "b": "2"
  }
}, {
  "key": "C",
  "value": [
    "a",
    "2"
  ]
}, {
  "key": "B",
  "value": true
}] */

Детская площадка ссылка на код

1
jcalz 14 Июн 2021 в 18:34

Это объединит любые повторяющиеся ключи, создав новое свойство values для хранения массива объединенных значений (из одинаковых ключей).

const array = [{key: 'A', value: 1},{key: 'A', value: 'str'},{key: 'C', value: { a: 1, b: '2'}},{key: 'B',value: true}]

const arrayUniqueByKey = [array.reduce((b, a) => {
  let f = b.findIndex(c => c.key === a.key)
  if (f === -1) return [...b, a];
  else {
    b[f].values = [...[b[f].value], a.value];
    return b
  }
}, [])];

console.log(arrayUniqueByKey)
0
Kinglish 14 Июн 2021 в 18:23