过滤由 id 键入的 json 并返回一个数组;没有未定义的地图

Posted

技术标签:

【中文标题】过滤由 id 键入的 json 并返回一个数组;没有未定义的地图【英文标题】:filtering in json keyed by id and returning an array; map without undefined 【发布时间】:2017-06-07 06:10:12 【问题描述】:

我有

let list =  
  1:  name: "someone1" ,
  5:  name: "someone5" ,
  7:  name: "someone7" ,
  8:  name: "someone8" 
;

我想过滤 [1,5,42]

[
  name: "someone1" ,
  name: "someone5" 
]

我试过了

Object.keys(list).map(key=> if([1,5,42].includes(key)) return list[key]);

[
  name: "someone1" ,
  name: "someone5",
 undefined, 
 undefined
]

PS:当我的列表是一个 json 数组时,我使用了list.filter(person => [1,5].includes(person.id))。然后我改为通过 id 模型键控,所以我可以使用liat[id],这比 list.filter 用于单个元素要快。

【问题讨论】:

【参考方案1】:

单线解决方案

[1,5,42].map(key => list[key]).filter(el => el)
// if(el != null) return true shortened as el => el

Nina Scholz 的简单单行:[1,5,42].reduce((r, k) => r.concat(list[k] || []), []); 的不同之处在于它在将其添加到数组之前进行检查,而上面的行在构建数组后删除了 undefineds。

另一种可能的单线是

["1","5","42"].filter(key => Object.keys(list).includes(key)).map(key => list[key])
//This one removes the invalid keys and then build an array without `undefined`s

片段

let list =  
  1:  name: "someone1" ,
  5:  name: "someone5" ,
  7:  name: "someone7" ,
  8:  name: "someone8" 
;

console.log([1,5,42].map(key => list[key]).filter(el => el));

console.log(["1","5","42"].filter(key => Object.keys(list).includes(key)).map(key => list[key]));

【讨论】:

原始问题中没有出现“单行”的要求。此答案中的javascript 与@NinaScholz 答案中的javascript 有何不同?您是否对每个答案中的javascript 完成流程所花费的时间进行了基准测试?从原始问题中不清楚实际要求是什么? One liner 不是原来的要求; 你的回答其实就是对我问题的回答,我可以用它;这些只是我想到的其他可能性....【参考方案2】:

您可以直接迭代过滤器数组并获取对象。

let list =  1:  name: "someone1" , 5:  name: "someone5" , 7:  name: "someone7" , 8:  name: "someone8"  ,
    filter = [1, 5],
    result = filter.map(k => list[k]);

console.log(result);

如果过滤器包含不是对象键的字符串,则需要一种不同的方法。

let list =  1:  name: "someone1" , 5:  name: "someone5" , 7:  name: "someone7" , 8:  name: "someone8"  ,
    filter = [1, 5, 42],
    result = filter.reduce((r, k) => r.concat(list[k] || []), []);

console.log(result);

一个两步解决方案,其中包含对象的映射值并使用Boolean 过滤真实元素。

let list =  1:  name: "someone1" , 5:  name: "someone5" , 7:  name: "someone7" , 8:  name: "someone8"  ,
    filter = [1, 5, 42],
    result = filter.map(key => list[key]).filter(Boolean);

console.log(result);

【讨论】:

可能是最简单的解决方案 我特别想要 42 部分..!在问题中进行了编辑 所以诀窍是,因为 map 总是返回一些东西,你使用 reduce 并推送到结果数组只有当它不是未定义...? @NinaScholz 现在我们有了答案,效率? :| @ZekeDran,你说的效率是什么意思?哪一个?两者都有 O(n)。【参考方案3】:

你可以使用解构赋值

let res = [];
(1:res[res.length], 5:res[res.length] = list);

let list =  
  1:  name: "someone1" ,
  5:  name: "someone5" ,
  7:  name: "someone7" ,
  8:  name: "someone8" 
;

let [keys, res] = [["1", "5"], []];

for (let key of keys) ([key]:res[res.length] = list)

console.log(res);

【讨论】:

您能解释一下这是如何工作的吗? (1:res[res.length], 5:res[res.length] = list); 当我有 42 个键(不存在的键)时会发生什么? @ZekeDran 1:res[res.length] 从对象获取属性"1" 并将值分配给res[res.length]。在第一个示例中,属性键是显式传递的。在for..of 循环中,当前数组元素是[] 中的计算属性名称。传递42"42" 的结果将是结果数组中的undefined 元素。在数组中传递不存在的属性的目的是什么? 列表单独获取,keys数组从服务端单独获取:keys在先!由于我使用的是 redux 存储,因此 list 最初将是 ,这使得键在那时无效,更不用说数组中的几个未定义会折叠整个应用程序 @ZekeDran 您可以在for..of 循环中包含if 语句并使用in 运算符或Object.prototype.hasOwnProperty()if (key in list) ([key]:res[res.length] = list)if (list.hasOwnProperty(key)) ([key]:res[res.length] = list)【参考方案4】:

let list =  
  1:  name: "someone1" ,
  5:  name: "someone5" ,
  7:  name: "someone7" ,
  8:  name: "someone8" 
;
function filter(ids, list)
  var ret = [];
  for(var i in ids)
    var id = ids[i];
    ret.push(list[id]);
  
  return ret;

var filtered = filter([1,5], list);
console.log(filtered);

此解决方案假定您只要求现有密钥。

【讨论】:

谢谢,但我对问题进行了编辑:如果undefineds 不存在,我特别需要删除它们

以上是关于过滤由 id 键入的 json 并返回一个数组;没有未定义的地图的主要内容,如果未能解决你的问题,请参考以下文章

PHP 过滤对象数组并返回新的对象数组,同时基于一个属性删除重复项

json_encode() 返回 false

Javascript通过包含搜索词的标签子数组过滤或减少每个JSON对象

jq 过滤内部数组元素但返回整个 JSON

Vue.js - 通过另一个 JSON 数组过滤 JSON 数组

过滤具有相同 ID 和给定条件的对象的 json 数组