如何使用lodash获取对象的前n个元素?

17

我想使用lodash从一个对象(而不是数组)中获取前n个键值对。我在这个underscore的答案中找到了使用first(在lodash中不存在),或者使用take(仅适用于数组)的方法。

示例节点会话,尝试从对象中获取'a:7'和'b:8'这两对键值:

> var ld=require("lodash")
undefined
> var o={a:7, b:8, c:9}
undefined
> ld.keys(o)
[ 'a', 'b', 'c' ]
> ld.take(o, 2)
[]
> ld.first(o, 2)
undefined
> 

肯定有一些使用lodash的简单方法来做到这一点,但我无论如何都找不到任何东西。也许我必须求助于本地的js吗?


你期望的输出是什么?[a,b]? - Samuel Toh
我期望得到 {a: 7, b: 8} -- 一个子集的“哈希”(对象),我更多地将其视为(类似于 Perl 的)哈希。 - vt5491
4
需要记住的一点是 - 对象中的“第一个”键完全没有意义。对象属性没有必要保持一致性,因此“前三个”理论上可以是任何三个。浏览器通常按插入顺序返回属性,但不要依赖于该行为。 - VLAZ
@vt5491 已更新我的解决方案以反映新的预期输出。 - Samuel Toh
3个回答

8

如果没有编写自定义代码,您将无法获取对象的前N个元素。这是因为对象中的元素没有排序, 因此,即使有库函数也不能保证给出您所期望的元素。例如给定一个对象

var obj = {  b: 3, y: 2, a: 1 };

不清楚“前2个”指的是什么——您是否想要ab,因为这是字母顺序?如果是,它们是否按照该顺序排列?如果没有,您是否想要by,因为它们首先出现?也许您想要ay,因为它们的值最小?

除了不重复之外,您得到的东西没有任何保证,因此所有这些组合都是有效的。此外,您可以按任何顺序获得它们,ya同样有效。您可能更喜欢其中一个,但一般来说并不正确。

有办法解决这个问题,但您必须接受需要处理非顺序的事实。

Pure JavaScript solution.

function firstN(obj, n) {
  return Object.keys(obj) //get the keys out
    .sort() //this will ensure consistent ordering of what you will get back. If you want something in non-aphabetical order, you will need to supply a custom sorting function
    .slice(0, n) //get the first N
    .reduce(function(memo, current) { //generate a new object out of them
      memo[current] = obj[current]
      return memo;
    }, {})
}
var obj = { b: 2, y: 25, a: 1 }

console.log( firstN(obj, 2) );

这里使用了Object.keysArray.prototype.sortArray.prototype.reduce
使用lodash也可以达到同样的效果,但并不比这更加简洁 - 它需要调用类似的功能。例如,可以这样实现:

function firstN(obj, n) {
  return _.chain(obj)
    .keys()
    .sort()
    .take(n)
    .reduce(function(memo, current) {
      memo[current] = obj[current];
      return memo;
    }, {})
    .value();
}

var obj = { b: 2, y: 25, a: 1 }
      
console.log( firstN(obj, 2) );
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

正如您所见,它与以前基本相同。语法和确切的执行方式可能会有所不同,但主要要点仍然存在 - 您需要进行一致性排序,然后就可以获得任意数量的项目。

是的,我喜欢这个因为它采用了函数式编程风格。 - vt5491
然而,我认为我正在学习lodash偏向于数组。虽然在数组中有哈希也是可以的,例如[{a:1}, {b:2}]。因此,也许最终的解决方案是避免使用哈希(对象)作为容器。但我也发现了lodash的“object”部分。在找到toPairs函数后,我运气不错:`> object = {a: 7, b: 8, c: 9} { a: 7, b: 8, c: 9 }
_.chain(object).toPairs(o).take(2).value() [ [ 'a', 7 ], [ 'b', 8 ] ]`
- vt5491
1
这是关于编程的内容:object = {a: 7, b: 8, c: 9}; _.chain(object).toPairs().take(2).value() 的返回值是:[ [ 'a', 7 ], [ 'b', 8 ] ] - vt5491
1
是的,如果适合您,您肯定可以使用 toPairs。 我发现很多时候,我不需要一个对象,而是一个 [key,value] 数组就足够了。 如果您确实需要一个对象,则可以从成对的数组创建一个对象。 我现在记不起函数的名称了(因为它不是逻辑上的 fromPairs ...),但这是可能的。 因此,您可以将 lodash 代码作为 toPairs,然后过滤这些内容,然后将这些成对的内容连接到一个新对象中。 - VLAZ

4
如果您查看loadash文档中的first函数,它只接受数组作为参数,这可能不是要使用的API。
请参阅:https://lodash.com/docs/3.10.1#first 以下是使用标准Javascript API解决此问题的一种方法。
关键点在于,您可以使用Object.keys(...)[index] API根据位置检索元素的键。
然后,您所需做的就是循环n次,并将其推入另一个对象中使用已派生的键。

var firstN = 2;
var o={a:7, b:8, c:9};
var result = {};

for (var index=0; index < firstN; index++) {
  var key = Object.keys(o)[index];
  result[key] = o[key];
}

console.log(result);


谢谢您的回复。所以您基本上是说lodash无法做到这一点。我尝试使用lodash的整个原因是为了避免编写样板,并开始思考“功能性”。但我确实赞赏对象无序等方面的观点。我不是在抨击您的回复,我很感激它,但我认为令人失望(并且有点令人惊讶)的是lodash没有提供此功能。就像我说的那样,这不是针对您的,只是关于lodash的一般观察。附言:我仍然喜欢lodash。 - vt5491
@vt5491 - 我明白了。你仍然可以使用 take 来实现你想要的功能。请查看我的更新答案。希望能在某种程度上帮到你。 - Samuel Toh
1
@vt5491 - 我为你做了一点研究,发现这个家伙也遇到了类似的问题 :P https://github.com/lodash/lodash/issues/946 - Samuel Toh
@SamuelToh - take并不完全相同。它不能用于对象,因此您只能提取键(或作为数组的键值对)并然后take其中的前N个,但是您无法直接执行_take(obj, 2)并获得包含两个(无论如何定义)属性的对象。 - VLAZ
另外,你提供的那个问题与 OP 的完全不同 - 它是关于 lodash 中不存在 first,而在 Underscore 中存在。这与在对象上使用 .take/.first 没有任何关系。 - VLAZ
@vlaz 好的,我明白了。等我晚些回家后,我会更新解决方案并去掉 take 部分,以使其不那么误导。感谢您的澄清。 - Samuel Toh

1

没有简单直接的解决方案。受以前的答案和评论启发,并阅读了一些关于非保证属性顺序的文章,我创建了一个解决方案,首先对键进行排序。

排序键

这里是一个可用的一行代码,使用排序的键(因此保证顺序)

链接

_.chain(object).toPairs().sortBy(0).take(2).fromPairs().value()

没有链接

_.fromPairs(_.take(_.sortBy(_.toPairs(object), 0), 2)),

排序详解

sortBy(0) 按照 (索引0)对我们的集合进行排序。首先,原始对象被转换为由一组对数组(每个是一个数组[key, value])组成的数组,然后按照这些的第一个值(中的key中具有索引0)进行排序。


重要提示: 如前面的答案和评论所述,即使在最新的ES版本中,属性的顺序也无法保证。请参见此更新的SO答案。因此我正在对键进行排序。


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