我想知道是否有一种已知的,内置/优雅的方法来查找匹配给定条件的JS数组的第一个元素。 C#的等价物是List.Find。
到目前为止,我一直在使用这样的双功能组合:
// Returns the first element of an array that satisfies given predicate
Array.prototype.findFirst = function (predicateCallback) {
if (typeof predicateCallback !== 'function') {
return undefined;
}
for (var i = 0; i < arr.length; i++) {
if (i in this && predicateCallback(this[i])) return this[i];
}
return undefined;
};
// Check if element is not undefined && not null
isNotNullNorUndefined = function (o) {
return (typeof (o) !== 'undefined' && o !== null);
};
然后我可以使用:
var result = someArray.findFirst(isNotNullNorUndefined);
但是既然有so many functional-style array methods in ECMAScript,也许那里已经有类似的东西?我想很多人不得不一直这样做......
答案 0 :(得分:147)
自ES6以来,阵列有本地find
method。
const result = someArray.find(isNotNullNorUndefined);
我必须发布一个答案来停止这些filter
建议: - )
因为ECMAScript中有很多功能样式的数组方法,或许还有类似的东西吗?
您可以使用some
Array method迭代数组,直到满足条件(然后停止)。不幸的是,它只会返回条件是否满足一次,而不是通过哪个元素(或在什么索引处)满足。所以我们必须稍微修改一下:
function find(arr, test, ctx) {
var result = null;
arr.some(function(el, i) {
return test.call(ctx, el, i, arr) ? ((result = el), true) : false;
});
return result;
}
var result = find(someArray, isNotNullNorUndefined);
答案 1 :(得分:91)
从ECMAScript 6开始,您可以使用Array.prototype.find
。这是在Firefox(25.0),Chrome(45.0),Edge(12)和Safari(7.1)中实现和使用的,但是not in Internet Explorer or a bunch of other old or uncommon platforms。
例如,下面的表达式计算为106
。
[100,101,102,103,104,105,106,107,108,109].find(function (el) {
return el > 105;
});
如果您想立即使用此功能但需要支持IE或其他不支持的浏览器,则可以使用垫片。我推荐es6-shim。如果由于某种原因您不想将整个es6-shim放入您的项目中,MDN还会提供a shim。为了获得最大的兼容性,您需要es6-shim,因为它与MDN版本不同,它会检测find
的错误本机实现并覆盖它们(请参阅以开头的注释“解决Array#find和Array#findIndex中的错误“以及紧随其后的行。”
答案 2 :(得分:52)
如何使用filter并从结果数组中获取第一个索引?
var result = someArray.filter(isNotNullNorUndefined)[0];
答案 3 :(得分:15)
现在应该很清楚JavaScript本身没有提供这样的解决方案;这里是最接近的两个衍生物,最有用的第一个:
Array.prototype.some(fn)
提供了满足条件时所需的停止行为,但仅返回元素是否存在;应用一些技巧并不难,例如Bergi's answer提供的解决方案。
Array.prototype.filter(fn)[0]
是一个很好的单行,但效率最低,因为你扔掉N - 1
元素只是为了得到你需要的东西。
JavaScript中的传统搜索方法的特点是返回找到的元素的索引而不是元素本身或-1。这避免了必须从所有可能类型的域中选择返回值;索引只能是数字,负值无效。
上面的两个解决方案都不支持偏移搜索,所以我决定写这个:
(function(ns) {
ns.search = function(array, callback, offset) {
var size = array.length;
offset = offset || 0;
if (offset >= size || offset <= -size) {
return -1;
} else if (offset < 0) {
offset = size - offset;
}
while (offset < size) {
if (callback(array[offset], offset, array)) {
return offset;
}
++offset;
}
return -1;
};
}(this));
search([1, 2, NaN, 4], Number.isNaN); // 2
search([1, 2, 3, 4], Number.isNaN); // -1
search([1, NaN, 3, NaN], Number.isNaN, 2); // 3
答案 4 :(得分:8)
如果您使用的是underscore.js
,则可以使用其find
和indexOf
功能获得您想要的内容:
var index = _.indexOf(your_array, _.find(your_array, function (d) {
return d === true;
}));
文档:
答案 5 :(得分:4)
ES6
find()
find()
位于Array.prototype
上,因此可以在每个数组上使用。find()
进行测试boolean
条件的回调。该函数返回值(不是索引!)
const array = [4, 33, 8, 56, 23];
const found = array.find((element) => {
return element > 50;
});
console.log(found); // 56
答案 6 :(得分:3)
自ES 2015起,Array.prototype.find()
提供了这一确切的功能。
对于不支持此功能的浏览器,Mozilla开发者网络提供了polyfill(粘贴在下方):
if (!Array.prototype.find) {
Array.prototype.find = function(predicate) {
if (this === null) {
throw new TypeError('Array.prototype.find called on null or undefined');
}
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
var list = Object(this);
var length = list.length >>> 0;
var thisArg = arguments[1];
var value;
for (var i = 0; i < length; i++) {
value = list[i];
if (predicate.call(thisArg, value, i, list)) {
return value;
}
}
return undefined;
};
}
答案 7 :(得分:2)
Array.prototype.find()就是这么做的,更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
答案 8 :(得分:0)
foundElement = myArray[myArray.findIndex(element => //condition here)];
答案 9 :(得分:0)
我从互联网上的多个来源获得了启发,并得出了以下解决方案。希望同时考虑一些默认值,并提供一种比较每个条目的方法,以解决此问题。
用法:(给出值“第二”)
var defaultItemValue = { id: -1, name: "Undefined" };
var containers: Container[] = [{ id: 1, name: "First" }, { id: 2, name: "Second" }];
GetContainer(2).name;
实施:
class Container {
id: number;
name: string;
}
public GetContainer(containerId: number): Container {
var comparator = (item: Container): boolean => {
return item.id == containerId;
};
return this.Get<Container>(this.containers, comparator, this.defaultItemValue);
}
private Get<T>(array: T[], comparator: (item: T) => boolean, defaultValue: T): T {
var found: T = null;
array.some(function(element, index) {
if (comparator(element)) {
found = element;
return true;
}
});
if (!found) {
found = defaultValue;
}
return found;
}
答案 10 :(得分:0)
使用findIndex
就像其他先前写的一样。这是完整的示例:
function find(arr, predicate) {
foundIndex = arr.findIndex(predicate);
return foundIndex !== -1 ? arr[foundIndex] : null;
}
用法如下(我们要在数组中找到第一个元素,其属性为id === 1
)。
var firstElement = find(arr, e => e.id === 1);
答案 11 :(得分:-1)
Javascript中没有内置函数来执行此搜索。
如果您使用的是jQuery,则可以执行jQuery.inArray(element,array)
。
答案 12 :(得分:-1)
一种不太优雅的方式throw
所有正确的错误消息(基于Array.prototype.filter
)但会停止迭代第一个结果
function findFirst(arr, test, context) {
var Result = function (v, i) {this.value = v; this.index = i;};
try {
Array.prototype.filter.call(arr, function (v, i, a) {
if (test(v, i, a)) throw new Result(v, i);
}, context);
} catch (e) {
if (e instanceof Result) return e;
throw e;
}
}
然后是例子
findFirst([-2, -1, 0, 1, 2, 3], function (e) {return e > 1 && e % 2;});
// Result {value: 3, index: 5}
findFirst([0, 1, 2, 3], 0); // bad function param
// TypeError: number is not a function
findFirst(0, function () {return true;}); // bad arr param
// undefined
findFirst([1], function (e) {return 0;}); // no match
// undefined
通过使用filter
来结束throw
。