根据其多个属性从数组中删除元素

3

I've an array of elements as follows

entities

[
  {
    "name":"tiger",
    "imageurl":"https://someurl.com",
    "type":"animal"
  },
  {
    "name":"cat",
    "imageurl":"https://someurl.com",
    "type":"animal"
  },
{
    "name":"parrot",
    "imageurl":"https://someurl.com",
    "type":"bird"
  },{
    "name":"potato",
    "imageurl":"https://someurl.com",
    "type":"vegetable"
  },
  {
    "name":"orange",
    "imageurl":"https://someurl.com",
    "type":"fruit"
  },
  {
    "name":"orange",
    "imageurl":"https://someurl.com",
    "type":"colour"
  }
]

我有另一个如下所示的数组

elemToRemove(要移除的元素)

[orange@fruit,cat@animal,tiger@animal]

我想要删除以下属性:name=orangetype=fruitname=cattype=animalname=tigertype=animal

如果是单个属性,可以使用数组过滤器轻松删除元素,但在这种情况下,我无法使用map/filter/reduce来删除这些元素。

我使用split创建了一个名称和类型的数组,并尝试进行操作,但由于类型重复,条件始终返回false。

 let nameArray = elemToRemove.map(function (elem) {
    return elem.split('@')[0];
  });

  let typeArray= elemToRemove.map(function (elem) {
    return elem.split('@')[1];
  });

  var reqData= entities.filter(function (obj) {
    return (nameArray.indexOf(obj.name) === -1 && typeArray.indexOf(obj['env']) === -1);
  }); 

因此,始终会给我一个空的reqData数组。我没有提供id,否则我可以使用id来删除元素。 期望输出
[
    {
        "name":"parrot",
        "imageurl":"https://someurl.com",
        "type":"bird"
      },{
        "name":"potato",
        "imageurl":"https://someurl.com",
        "type":"vegetable"
      },
      {
        "name":"orange",
        "imageurl":"https://someurl.com",
        "type":"colour"
      }
    ]

最优雅的方法是什么,可以实现这一点?

1
首先,"JSON对象"实际上并不存在。 - Muhammad Usman
1
当你说“我不能使用map/filter/reduce”时,你是指你不会使用它们吗?还是你不知道如何使用它们? - Jorjon
哦,我的意思是我尝试使用代码片段中提到的过滤器/映射/归约等方法,但未能获得有效的输出。我可以使用任何东西,这不是一个测试或作业:D - TGW
@Usman 谢谢你指出,我会立即进行编辑。 - TGW
4个回答

4

Map 常用于此类问题,并带有 次线性 的价值检索奖励。

// Input.
const input = [{"name":"tiger","imageurl":"https://someurl.com","type":"animal"},{"name":"cat","imageurl":"https://someurl.com","type":"animal"},{"name":"parrot","imageurl":"https://someurl.com","type":"bird"},{"name":"potato","imageurl":"https://someurl.com","type":"vegetable"},{"name":"orange","imageurl":"https://someurl.com","type":"fruit"},{"name":"orange","imageurl":"https://someurl.com","type":"colour"}]

// Tags.
const tags = ["orange@fruit", "cat@animal", "tiger@animal"]

// Clean.
const clean = (array, tags) => {
  const map = new Map(array.map(x => [`${x.name}@${x.type}`, x])) // Create Map.
  tags.forEach(tag => map.delete(tag)) // Remove each tag from Map.
  return Array.from(map.values()) // Return Array from Map.values().
}

// Output.
const output = clean(input, tags)

// Proof.
console.log(output)


这个答案肯定会受益于一些解释; "clean"函数简洁到对那些没有很好理解Map等的人来说是难以理解的。 - Daniel Beck
1
不好的习惯。我同意重构。@DanielBeck - Arman Charan
1
不要误会,这是好的代码!只是对于非专家来说有点难以理解。 - Daniel Beck

1
如果您对“优雅”的定义是尽可能少的代码(以避免人为错误),并且重用其他人已经创建的元素,则建议使用像Lodash这样的外部库,它已经有一个函数来实现这一点。
第一部分有点复杂,因为我要从一个字符串开始:
[orange@fruit,cat@animal,tiger@animal]
需要进行解析,而不是像其他答案那样已经有一个值数组。
// First we need to convert the filter to a proper Json representation.
// This is needed since the _.remove function takes a Json object.
// This could be simplified if your filter string were already a
// Json object.
var filter = "[orange@fruit,cat@animal,tiger@animal]";
filter = filter.replace(/(\w+)@(\w+)[,\]]/g, (m, p1, p2, offset, string) => {
    return `{"name":"${p1}","type":"${p2}"}${m.includes(']')?']':','}`;
});
filter = JSON.parse(filter);


// Next, apply the filter to the remove function from Lodash.
// Once you have a Json object, it's only two lines of code.
const rm = _.partial(_.remove, obj);
filter.forEach(rm)

var obj = [
  {
    "name":"tiger",
    "imageurl":"https://someurl.com",
    "type":"animal"
  },
  {
    "name":"cat",
    "imageurl":"https://someurl.com",
    "type":"animal"
  },
{
    "name":"parrot",
    "imageurl":"https://someurl.com",
    "type":"bird"
  },{
    "name":"potato",
    "imageurl":"https://someurl.com",
    "type":"vegetable"
  },
  {
    "name":"orange",
    "imageurl":"https://someurl.com",
    "type":"fruit"
  },
  {
    "name":"orange",
    "imageurl":"https://someurl.com",
    "type":"colour"
  }
];

// First we need to convert the filter to a proper Json representation.
// This is needed since the _.remove function takes a Json object.
// This could be simplified if your filter string were already a
// Json object.
var filter = "[orange@fruit,cat@animal,tiger@animal]";
filter = filter.replace(/(\w+)@(\w+)[,\]]/g, (m, p1, p2, offset, string) => {
    return `{"name":"${p1}","type":"${p2}"}${m.includes(']')?']':','}`;
});
filter = JSON.parse(filter);


// Next, apply the filter to the remove function from Lodash.
// Once you have a Json object, it's only two lines of code.
const rm = _.partial(_.remove, obj);
filter.forEach(rm)

console.log(obj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>


1
你可以使用 filter() 来选择那些不符合所需条件的对象。我们将使用 .some() 测试每个对象,以查找对象和包含要检查的字符串的数组之间是否存在匹配项。

let data = [{"name":"tiger", "imageurl":"https://someurl.com", "type":"animal"}, {"name":"cat", "imageurl":"https://someurl.com", "type":"animal"}, {"name":"parrot", "imageurl":"https://someurl.com", "type":"bird"}, { "name":"potato", "imageurl":"https://someurl.com", "type":"vegetable"}, { "name":"orange", "imageurl":"https://someurl.com", "type":"fruit"}, { "name":"orange", "imageurl":"https://someurl.com", "type":"colour"}];

let arr = ['orange@fruit', 'cat@animal', 'tiger@animal'];

let result = data.filter(o => !arr.some(s => (
    [name, type] = s.split('@'),
    o['name'] === name && o['type'] === type
)));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

文档:


1
为什么会有人对这个答案进行踩票?它是正确且能够产生预期结果的啊! - Randy Casburn
我不认为有理由进行负面评价,因为它确实可以得到所需的输出。 - TGW

1
您可以使用 array.filter:

var arr = [
  {"name":"tiger","imageurl":"https://someurl.com","type":"animal"},
  {"name":"cat","imageurl":"https://someurl.com","type":"animal"},
  {"name":"parrot","imageurl":"https://someurl.com","type":"bird"},
  {"name":"potato","imageurl":"https://someurl.com","type":"vegetable"},
  {"name":"orange","imageurl":"https://someurl.com","type":"fruit"},
  {"name":"orange","imageurl":"https://someurl.com","type":"colour"}
];

var toRemove = ['orange@fruit', 'cat@animal', 'tiger@animal'];
var filterOut = toRemove.map(e => { 
  var [name, type] = e.split('@');
  return {name, type};
});
arr = arr.filter(e => !filterOut.find(({name, type}) => e.name === name && e.type === type));

console.log(arr);


1
为什么有人会对这个答案点踩?它是有效的并且产生了预期的结果! - Randy Casburn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接