按照另一个数组的顺序从另一个数组中匹配属性的对象中筛选出对象

时间:2018-09-27 13:28:11

标签: javascript arrays lodash

在我的职业生涯中,我多次遇到这个问题。我已经用谷歌搜索,但没有在那些结果或StackOverflow上找到精确匹配。

考虑到我有以下对象数组:

let objects = [
    {id: 'doe', descr: 'a deer'},
    {id: 'baz', descr: 'non-sense'},
    {id: 'ray', descr: 'a drop'},
    {id: 'foo', descr: 'effed'},
    {id: 'bar', descr: 'beyond'}
];

我只想获取id与以下数组之一匹配的数组元素, 将它们返回与 order匹配的数组

let objectsOrder = ['foo', 'bar', 'baz'];

我实际上已经设计了几种解决方案,并且将在下面使用reduce提出一个解决方案(我在其他尝试中也使用过forEach,但不会提出解决方案)。我猜也可以先过滤,然后再(自定义)排序,但这似乎要重复两次。也许另一种选择是使用lodash中的一种或多种方法,尽管我不确定那会是什么。

5 个答案:

答案 0 :(得分:2)

您可以使用Map并按所需顺序映射对象。

var objects = [
        { id: 'doe', descr: 'a deer' }, 
        { id: 'baz', descr: 'non-sense' }, 
        { id: 'ray', descr: 'a drop' }, 
        { id: 'foo', descr: 'effed' }, 
        { id: 'bar', descr: 'beyond' }
    ],
    objectsOrder = ['foo', 'bar', 'baz'],
    result = objectsOrder.map(Map.prototype.get, new Map(objects.map(o => [o.id, o])));

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

如果某些id未知,则可以为真实项目添加过滤器。

var objects = [
        { id: 'doe', descr: 'a deer' }, 
        { id: 'baz', descr: 'non-sense' }, 
        { id: 'ray', descr: 'a drop' }, 
        { id: 'foo', descr: 'effed' }, 
        { id: 'bar', descr: 'beyond' }
    ],
    objectsOrder = ['foo', 'bar', 'unknown'],
    result = objectsOrder
        .map(Map.prototype.get, new Map(objects.map(o => [o.id, o])))
        .filter(Boolean);

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

答案 1 :(得分:0)

以下代码位于:https://repl.it/@dexygen/orderFilteredObjects

let objects = [
    {id: 'doe', descr: 'a deer'},
    {id: 'baz', descr: 'non-sense'},
    {id: 'ray', descr: 'a drop'},
    {id: 'foo', descr: 'effed'},
    {id: 'bar', descr: 'beyond'}
];

let objectsOrder = ['foo', 'bar', 'baz'];

let prunedObjects = objects.reduce((pruned, obj) => {
    let orderIndex = objectsOrder.indexOf(obj.id);
    if (orderIndex >= 0) {
      pruned[orderIndex] = obj;
    }
    return pruned;
}, []);

console.log(JSON.stringify(prunedObjects)); //[{"id":"foo","descr":"effed"},{"id":"bar","descr":"beyond"},{"id":"baz","descr":"non-sense"}]

答案 2 :(得分:0)

这可以轻松地通过forEach()循环来完成。无需使用reduce()

let objects = [
    {id: 'doe', descr: 'a deer'},
    {id: 'baz', descr: 'non-sense'},
    {id: 'ray', descr: 'a drop'},
    {id: 'foo', descr: 'effed'},
    {id: 'bar', descr: 'beyond'}
];

let objectsOrder = ['foo', 'bar', 'baz'];
let res = [];
objects.forEach((obj)=>{
  var id = obj.id;
  var idIndex = objectsOrder.indexOf(id);
  if(idIndex !== -1){
    res[idIndex] = obj;
  }
});
console.log(res);

答案 3 :(得分:0)

另一种方法是通过lodash _.keyBy以适合对象键访问的形式获取输入数据:

let objects = [{id: 'doe', descr: 'a deer'},{id: 'baz', descr: 'non-sense'},{id: 'ray', descr: 'a drop'},{id: 'foo', descr: 'effed'},{id: 'bar', descr: 'beyond'}];
let objectsOrder = ['foo', 'bar', 'baz'];

var keyedObjects = _.keyBy(objects, 'id')
var result = objectsOrder.map(x => keyedObjects[x])

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

通过这种方式,您可以在objectsOrder上进行映射以保留订单,只需使用键即可在map函数中获得访问权限。

答案 4 :(得分:-1)

您不需要如此复杂的逻辑。只需映射每个objectsOrder值并在objects数组上获取相应的值

let objects = [
    {id: 'doe', descr: 'a deer'},
    {id: 'baz', descr: 'non-sense'},
    {id: 'ray', descr: 'a drop'},
    {id: 'foo', descr: 'effed'},
    {id: 'bar', descr: 'beyond'}
];

let objectsOrder = ['foo', 'bar', 'baz'];

console.log(
  objectsOrder.map(a=>objects.find(b=>b.id==a))
)