如何在JavaScript中找到匹配布尔条件的数组的第一个元素?

我想知道是否有一个已知的,内置/优雅的方法来找到一个JS数组的第一个元素匹配给定的条件。c#的等效函数是列表。找到

到目前为止,我一直在使用这样的双功能组合:

// 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);

但是既然有ECMAScript中有这么多函数风格的数组方法,也许已经有这样的东西了?我想很多人都必须实现这样的东西……

479593 次浏览

Javascript中没有内置函数来执行此搜索。

如果你正在使用jQuery,你可以做jQuery.inArray(element,array)

那么使用过滤器并从结果数组中获取第一个索引呢?

var result = someArray.filter(isNotNullNorUndefined)[0];

一种不太优雅的方法是将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

它通过使用throw结束filter来工作。

自ES6以来,数组有原生的find方法;一旦找到第一个匹配项并返回值,就停止枚举数组。

const result = someArray.find(isNotNullNorUndefined);

旧的回答:

我必须发布一个答案来阻止这些filter的建议:-)

既然ECMAScript中有这么多函数风格的数组方法,也许已经有这样的东西了?

可以使用some数组方法迭代数组,直到满足条件(然后停止)。不幸的是,它只返回条件是否满足过一次,而不是由哪个元素(或在哪个索引处)满足的。所以我们要稍微修改一下:

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);

如果你正在使用underscore.js,你可以使用它的findindexOf函数来得到你想要的:

var index = _.indexOf(your_array, _.find(your_array, function (d) {
return d === true;
}));

文档:

  • < a href = " http://underscorejs.org/找到" > http://underscorejs.org/找到< / >
  • < a href = " http://underscorejs.org/ indexOf " > http://underscorejs.org/ indexOf < / >

现在应该清楚了,JavaScript本身并没有提供这样的解决方案;下面是最接近的两个导数,第一个最有用:

  1. Array.prototype.some(fn)提供了当条件满足时所需的停止行为,但只返回元素是否存在;使用一些技巧并不难,例如Bergi的答案提供的解决方案。

  2. 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

从ECMAScript 6开始,你可以使用Array.prototype.find。这是在Firefox (25.0), Chrome (45.0), Edge(12)和Safari(7.1)中实现和工作的,但是而不是在ie浏览器或其他一堆旧的或不常见的平台上

例如,下面的x106:

const x = [100,101,102,103,104,105,106,107,108,109].find(function (el) {
return el > 105;
});
console.log(x);

如果你现在想使用这个,但需要IE或其他不支持的浏览器的支持,你可以使用shim。我推荐es6-shim。如果出于某种原因你不想把整个es6-shim放到你的项目中,MDN也提供了一个垫片。为了获得最大的兼容性,你需要es6-shim,因为与MDN版本不同,它会检测有bug的find本机实现并覆盖它们(参见解决Array#find和Array#findIndex"中的bug;开头的注释及其后面的行)。

从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;
};
}

简介:

  • 为了找到数组中第一个符合布尔条件的元素,我们可以使用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

foundElement = myArray[myArray.findIndex(element => //condition here)];

我从互联网上的多个来源获得灵感,推导出下面的解决方案。希望考虑到一些默认值,并提供一种方法来比较每个条目的通用方法,这就解决了。

用法:(给出值“秒”)

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;
}

使用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);
      const employees = [
{id: 1, name: 'Alice', country: 'Canada'},
{id: 2, name: 'Bob', country: 'Belgium'},
{id: 3, name: 'Carl', country: 'Canada'},
{id: 4, name: 'Dean', country: 'Germany'},
];
    

// 👇️ filter with 1 condition
const filtered = employees.filter(employee => {
return employee.country === 'Canada';
});
// 👇️ [{id: 1, name: 'Alice', country: 'Canada'},
//     {id: 3, name: 'Carl', 'country: 'Canada'}]
console.log(filtered);
    

// 👇️ filter with 2 conditions
const filtered2 = employees.filter(employee => {
return employee.country === 'Canada' && employee.id === 3;
});
    

// 👇️ [{id: 3, name: 'Carl', country: 'Canada'}]
console.log('filtered2: ', filtered2);
    

const employee = employees.find(obj => {
return obj.country === 'Canada';
});


// 👇️ {id: 1, name: 'Alice', country: 'Canada'}
console.log(employee);