【问题标题】:Remove element from an array based on it's multiple peoperties根据多个属性从数组中删除元素
【发布时间】:2018-09-12 19:14:02
【问题描述】:

我有一个元素数组如下

实体

[
  {
    "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"
      }
    ]

实现此目的最优雅的方法是什么?

【问题讨论】:

  • 首先真的没有“JSON 对象”这样的东西。
  • 当您说I am not able to put up map/filter/reduce 时,您的意思是您不能使用它们?或者你不知道怎么做?
  • 哦,我的意思是我尝试以代码 sn-p 中提到的方式或其他方式使用 filter/map/reduce,但未能获得有效的输出,我绝对可以使用任何它是不是测试或作业:D
  • @Usman 感谢指出,我会马上修改

标签: javascript arrays json iteration


【解决方案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>

【讨论】:

    【解决方案2】:

    您可以使用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; }

    文档:

    【讨论】:

    • 为什么有人会否决这个答案?它是有效的并产生预期的结果!
    • 我看不出投反对票的原因,它也确实得到了所需的输出
    【解决方案3】:

    Map 往往对这些类型的问题很有用,并带有sublinear 值检索的好处。

    // 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)

    【讨论】:

    • 这个答案肯定可以从一些解释中受益; “干净”功能简洁到难以理解的程度,对于尚未对 Map 等有很好理解的人来说
    • 坏习惯。我同意?重构。 @丹尼尔贝克
    • 别误会,这是好代码!对于非专家来说有点难以理解
    【解决方案4】:

    你可以使用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);

    【讨论】:

    • 为什么有人会否决这个答案?它是有效的并产生预期的结果!
    猜你喜欢
    • 2013-02-23
    • 2018-10-31
    • 1970-01-01
    • 1970-01-01
    • 2016-01-22
    • 1970-01-01
    • 2011-05-26
    相关资源
    最近更新 更多