首页 > 解决方案 > 如何通过多个相同的属性过滤对象数组

问题描述

如何按照问题中的说明过滤此数组

描述

请注意,entry1entry4共享和的相同property: 'subject'property: 'field'

问题

我正在寻找一种高效且干净的方法来过滤此数组并获取与这些ies共享两个 values的条目。property

更新:

返回值

我不是试图转换数据,而是分析它。因此分析的返回值应如下所示:

[['entry1', 'entry4'],...]

并且通过这个分析列表,我可以轻松地将我triples = [...]的列表转换为三元组列表,在其中删除一个条目(无关紧要,可以是“entry1”或“entry4”),并更新另一个

[
  { subject: "entry1", property: "subject", value: "sport" },
  { subject: "entry1", property: "field", value: "category" },
  { subject: "entry1", property: "content", value: "football" },
  { subject: "entry1", property: "content", value: "basketball" },
]

附言

  1. 我不是在寻找这样的解决方案

    array.filter(({property, value})=> property === 'sport' && value === 'category')

我不知道“运动”或“类别”。这些是动态值。

  1. 我的实际数据要大得多,并且每个条目包含更多的属性类型。它也没有我在这里展示的那么好。我确实简化了它,所以请记住性能。

代码片段:

const triples = [
  { subject: "entry1", property: "subject", value: "sport" },
  { subject: "entry1", property: "field", value: "category" },
  { subject: "entry1", property: "content", value: "football" },
  
  { subject: "entry4", property: "subject", value: "sport" },
  { subject: "entry4", property: "field", value: "category" },
  { subject: "entry4", property: "content", value: "basketball" },
  
  { subject: "entry2", property: "subject", value: "music" },
  { subject: "entry2", property: "field", value: "category" },
  { subject: "entry2", property: "content", value: "notes" },
  
  { subject: "entry3", property: "subject", value: "painting" },
  { subject: "entry3", property: "field", value: "category" },
  { subject: "entry3", property: "content", value: "drawings" }
];

标签: javascriptarraysperformancefilteringlodash

解决方案


我必须说输入数据结构不是最优的,并且使用“主题”作为真实对象属性和值 property使其更加混乱。我将第一个概念(真正的 subject)称为“条目”,因为样本值为“entry1”、“entry2”、...。

这是一种提取["entry1", "entry4"]样本数据的方法:

  1. 通过将数据输入到对象中进行分组,其中“属性”和“值”被转换为键/值对,因此您将得到如下内容:

    {
        entry1: { subject: "sport", field: "category", content: "football" },
        entry4: { subject: "sport", field: "category", content: "basketball" },
        entry2: { subject: "music", field: "category", content: "notes" },
        entry3: { subject: "painting", field: "category", content: "drawings" }
    }
    

    这将更容易使用。下面的代码实际上会创建一个Map而不是一个普通的对象,但它是相同的原理。

  2. 为这些对象定义一个新group属性,其中值由主题和字段组成,字符串化为 JSON。例如,上述结果的第一个对象将扩展为:

    group: '["sport","category"]'
    
  3. 创建一个条目映射,由它们的组值键控。所以这将给出这个结果:

    {
        '["sport","category"]': ["entry1","entry4"],
        '["music","category"]': ["entry2"],
        '["painting","category"]': ["entry3"]
    }
    
  4. 现在,仅列出值(子数组)以及仅列出具有多个条目值的值是一个简单的步骤。

这是实现:

const triples = [{subject: "entry1", property: "subject", value: "sport"},{subject: "entry1", property: "field", value: "category"},{subject: "entry1", property: "content", value: "football"},{subject: "entry4", property: "subject", value: "sport"},{subject: "entry4", property: "field", value: "category"},{subject: "entry4", property: "content", value: "basketball"},{subject: "entry2", property: "subject", value: "music"},{subject: "entry2", property: "field", value: "category"},{subject: "entry2", property: "content", value: "notes"},{subject: "entry3", property: "subject", value: "painting"},{subject: "entry3", property: "field", value: "category"},{subject: "entry3", property: "content", value: "drawings"},];

// 1. Group the data by subject into objects where "property" and "value" are translated into key/value pairs:
const entries = new Map(triples.map(o => [o.subject, { entry: o.subject }]));
triples.forEach(o => entries.get(o.subject)[o.property] = o.value);
// 2. Define a group value for these objects (composed of subject and field)
entries.forEach(o => o.group = JSON.stringify([o.subject, o.field]));
// 3. Create Map of entries, keyed by their group value
const groups = new Map(Array.from(entries.values(), o => [o.group, []]));
entries.forEach(o => groups.get(o.group).push(o.entry));
// 4. Keep only the subarrays that have more than one value
const result = [...groups.values()].filter(group => group.length > 1);
console.log(result);

请注意,输出是一个嵌套数组,因为理论上可能有更多组合条目,例如[ ["entry1", "entry4"], ["entry123", "entry521", "entry951"] ]

以上可以修改/扩展以获得最终的过滤结果。在第三步中,您仍将收集对象(不仅仅是条目值),然后将过滤后的结果映射回原始格式:

const triples = [{subject: "entry1", property: "subject", value: "sport"},{subject: "entry1", property: "field", value: "category"},{subject: "entry1", property: "content", value: "football"},{subject: "entry4", property: "subject", value: "sport"},{subject: "entry4", property: "field", value: "category"},{subject: "entry4", property: "content", value: "basketball"},{subject: "entry2", property: "subject", value: "music"},{subject: "entry2", property: "field", value: "category"},{subject: "entry2", property: "content", value: "notes"},{subject: "entry3", property: "subject", value: "painting"},{subject: "entry3", property: "field", value: "category"},{subject: "entry3", property: "content", value: "drawings"},];

// 1. Group the data by subject into objects where "property" and "value" are translated into key/value pairs:
const entries = new Map(triples.map(o => [o.subject, { entry: o.subject }]));
triples.forEach(o => entries.get(o.subject)[o.property] = o.value);
// 2. Define a group value for these objects (composed of subject and field)
entries.forEach(o => o.group = JSON.stringify([o.subject, o.field]));
// 3. Create Map of objects(*), keyed by their group value
const groups = new Map(Array.from(entries.values(), o => [o.group, []]));
entries.forEach(o => groups.get(o.group).push(o));
// 4. Keep only the subarrays that have more than one value
const result = [...groups.values()].filter(group => group.length > 1)
// 5. ...and convert it back to the original format:
    .flatMap(group => [
        { subject: group[0].entry, property: "subject", value: group[0].subject },
        { subject: group[0].entry, property: "field", value: group[0].field },
        ...group.map(o => ({ subject: group[0].entry, property: "content", value: o.content }))
    ]);

console.log(result);


推荐阅读