在对象数组中查找最后匹配的对象

Gra*_*eck 15 javascript arrays

我有一个对象数组.我需要获取最后一个对象的对象类型(在此示例中为"shape"),将其删除,然后在数组中找到具有相同类型的前一个对象的索引,例如"shape".

var fruits = [
    { 
        shape: round,
        name: orange
    },
    { 
        shape: round,
        name: apple
    },
    { 
        shape: oblong,
        name: zucchini
    },
    { 
        shape: oblong,
        name: banana
    },
    { 
        shape: round,
        name: grapefruit
    }
]

// What's the shape of the last fruit
var currentShape =  fruits[fruits.length-1].shape;

// Remove last fruit
fruits.pop(); // grapefruit removed

// Find the index of the last round fruit
var previousInShapeType = fruits.lastIndexOf(currentShape);
    // should find apple, index = 1
Run Code Online (Sandbox Code Playgroud)

所以,显然这个例子中的类型将是"圆形".但我不是在寻找"圆"的数组值.我正在寻找fruits.shape = round的地方.

var previousInShapeType = fruits.lastIndexOf(fruits.shape = currentShape);
Run Code Online (Sandbox Code Playgroud)

但只是使用它不起作用.我确定我错过了一些简单的事情.如何在数组中找到对象形状=圆形的最后一项?

Luk*_*Liu 26

var fruit = fruits.slice().reverse().find(fruit => fruit.shape === currentShape);
Run Code Online (Sandbox Code Playgroud)

  • 对于那些想知道为什么需要 slice() 的人来说:reverse() 正在发生变化!slice() 为您提供了一个可供处理的副本。 (36认同)
  • 可以像 `constfruit = [...fruits].reverse().find(fruit =>fruit.shape === currentShape); 那样完成 ` (4认同)
  • @Pawel 取决于数组的大小以及执行操作的频率。在我看来,微观层面上的性能胜利通常是可读性和可维护性的一个不错的权衡 (4认同)
  • 也许看起来比接受的答案更干净,但是复制和反转数组并不是查找元素的有效方法。 (3认同)
  • 可读性始终是相对的(因为它是主观的)。对我来说,与 for 循环相比,这个解决方案需要更少的认知负载来解析。我并不是说 for 循环很难阅读,但是没有编码背景的人也可以理解这个解决方案,因为它读起来几乎像英语或伪代码。在过去的几年里,我越来越重视代码的阅读体验,并且更喜欢这个解决方案而不是 for 循环(即使后者性能更高)。关于这件事我只想说两分钱。 (2认同)

Nen*_*vic 18

更新 - 2021 年 10 月 27 日(Chrome 97+)

\n

提案现已Array.prototype.findLast进入第3Array.prototype.findLastIndex阶段4!

\n

以下是如何使用它们:

\n
const fruits = [\n  { shape: \'round\', name: \'orange\' },\n  { shape: \'round\', name: \'apple\' },\n  { shape: \'oblong\', name: \'zucchini\' },\n  { shape: \'oblong\', name: \'banana\' },\n  { shape: \'round\', name: \'grapefruit\' }\n]\n\nlet last_element = fruits.findLast((item) => item.shape === \'oblong\');\n// \xe2\x86\x92 { shape: oblong, name: banana }\n\nlet last_element_index = fruits.findLastIndex((item) => item.shape === \'oblong\');\n// \xe2\x86\x92 3\n
Run Code Online (Sandbox Code Playgroud)\n

您可以在这篇 V8 博客文章中阅读更多内容。

\n

您可以在“Chrome 新增功能”系列中找到更多内容。

\n


Den*_*Den 17

您可以将数组转换为数组boolean类型并获取最后一个true索引。

const lastIndex = fruits.map(fruit => 
  fruit.shape === currentShape).lastIndexOf(true);
Run Code Online (Sandbox Code Playgroud)

  • 对于小数组和简单条件非常有效,但否则效率很低,因为它将处理所有数组 (3认同)
  • 超级优雅的解决方案 (2认同)

Anu*_*rya 11

使用Lodash 库,您可以找到最后一个逻辑元素。

_.findLast([1,2,3,5,4], n => n % 2 == 1); // Find last odd element
// expected output: 5
Run Code Online (Sandbox Code Playgroud)


Ed *_*d I 7

这是一个不依赖于 的解决方案,reverse因此不需要“克隆”原始集合。

const lastShapeIndex = fruits.reduce((acc, fruit, index) => (
    fruit.shape === currentShape ? index : acc
), -1);
Run Code Online (Sandbox Code Playgroud)

  • @avioli,谢谢你的这两点。我用这些更改编辑了答案。 (2认同)

Ath*_*ace 5

var previousInShapeType, index = fruits.length - 1;
for ( ; index >= 0; index--) {
    if (fruits[index].shape == currentShape) {
        previousInShapeType = fruits[index];
        break;
    }
}
Run Code Online (Sandbox Code Playgroud)

您还可以向后遍历数组。

小提琴:http : //jsfiddle.net/vonn9xhm/

  • 这是最快的解决方案,执行速度为 55,323,764 操作/秒,而以下解决方案的平均执行速度为 2,200 操作/秒(快 25 000 倍)-(在最新的 google chrome 上测试了 100k 水果的集合)。但是!如果我们不关心一次反向收集的成本,并且缓存反向副本,那么 .reverse().find 解决方案实际上会以 55,853,952 ops/s 的速度执行得更快 (3认同)
  • 过早的优化可能会破坏可维护性,进而破坏真正重要的优化。不要为了可忽略的优化而牺牲可维护性。 (3认同)
  • @Artless 太高效了,他写了“to”而不是“for”,写了“efficient”而不是“efficiency”,节省了两个完整的字符! (3认同)
  • 这是这里唯一的正确答案。人们不再关注效率了吗? (2认同)
  • 同意,我想说,函数式编程破坏了效率 (2认同)
  • 此外,在大多数情况下,代码应该针对可维护性而不是效率进行优化,除非您绝对需要它。如果您知道您将得到一个简短的列表,请使用可读的方法。 (2认同)

Vik*_*ukh 5

一种更简单且相对有效的解决方案。过滤和流行!

过滤所有与当前形状匹配的水果,然后弹出以获取最后一个。

fruits.filter(({shape}) => shape === currentShape).pop()

var fruits = [{
    shape: 'round',
    name: 'orange'
}, {
    shape: 'round',
    name: 'apple'
}, {
    shape: 'oblong',
    name: 'zucchini'
}, {
    shape: 'oblong',
    name: 'banana'
}, {
    shape: 'round',
    name: 'grapefruit'
}];

// What's the shape of the last fruit
var currentShape = fruits[fruits.length - 1].shape;

// Remove last fruit
fruits.pop(); // grapefruit removed


alert(fruits.filter(({shape}) => shape === currentShape).pop().name);
Run Code Online (Sandbox Code Playgroud)