如何使用 javascript 根据字符串进行过滤,同时忽略其中的数字
How to filter based on string while disregarding the number in it using javascript
我有一个要过滤的列列表,现在我正在使用此逻辑:
for (const columnName of this.columnNames) {
const matchingColumns = fieldsForSearch.filter(c => columnName === c ||
columnName.match(c + '[ ][0-9]*$'));
if (matchingColumns && matchingColumns.length > 0) {
// do something...
}
}
这工作正常,但是,当我有一个巨大的数组时,它会花费很多时间,尤其是 .match
我怎样才能让它更快?使用 .test
或者 .startsWith
?
我过滤的 this.columnNames
可以有 Color
、Color 1
、Color 2
等值。这就是为什么我有这样的逻辑:
columnName.match(c + '[ ][0-9]*$'))
它也可以有这样的值:Age Range
、Age Range Minimum
、Age Range Maximum
。
我想要的是过滤名称和号码,所以在我上面的代码中,颜色,颜色 1... 通过,但 Age Range Minimum
没有。
示例输入:
['Color', 'Color 1', 'Color 2', 'Color 3', 'Age Range', 'Age Range Minimum', 'Age Range Maximum']
示例输出:
['Color', 'Color 1', 'Color 2', 'Color 3']
对于 OP 的用例,一种有效的方法是使用正则表达式,该正则表达式将匹配任何仅由空格分隔的非数字字符序列的字符串。像... /^(?:\D+\s+\D+)(?:\s+\D+)*$/
... Thus one matches exactly those strings, the OP wants to reject. A filter function then uses the negated return value of RegExp.prototype.test
...
const sampleInput = ['Color', 'Color 1', 'Color 2', 'Color 3', 'Age Range', 'Age Range Minimum', 'Age Range Maximum'];
const expectedResult = ['Color', 'Color 1', 'Color 2', 'Color 3'];
// matches any string wich is a sequence of
// whitespace separated non digit characters.
// see ... [https://regex101.com/r/6EBe7U/1/]
const regXWsSeparatedNonDigitSequence = (/^(?:\D+\s+\D+)(?:\s+\D+)*$/);
console.log(
sampleInput, ' =>',
sampleInput.filter(item =>
!regXWsSeparatedNonDigitSequence.test(item)
)
);
console.log(
'test passed ?',
sampleInput.filter(item =>
!regXWsSeparatedNonDigitSequence.test(item)
).join(',') === expectedResult.join(',')
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
顺便说一句……正则表达式的性能根本不是问题。
下一次过滤两次 70,000 个条目的测试确实证明了这一点(两次不到 7 毫秒)...
const regXWsSeparatedNonDigitSequence = (/^(?:\D+\s+\D+)(?:\s+\D+)*$/);
let testData = new Array(10_000);
let result;
// create an array of 70_000 string entries (10_000 x 7(string item count))
testData = testData
.fill(['Color', 'Color 1', 'Color 2', 'Color 3', 'Age Range', 'Age Range Minimum', 'Age Range Maximum'])
.flat(1);
// test with regex reference.
console.time("70,000 regX tests (reference) :: filter duration");
result = testData.filter(item =>
!regXWsSeparatedNonDigitSequence.test(item)
)
console.timeEnd("70,000 regX tests (reference) :: filter duration");
console.log('test passed ?.. ', (result.length === 40_000));
// test with regex literal.
console.time("70,000 regX tests (literal) :: filter duration");
result = testData.filter(item =>
!(/^(?:\D+\s+\D+)(?:\s+\D+)*$/).test(item)
)
console.timeEnd("70,000 regX tests (literal) :: filter duration");
console.log('test passed ?.. ', (result.length === 40_000));
.as-console-wrapper { min-height: 100%!important; top: 0; }
我有一个要过滤的列列表,现在我正在使用此逻辑:
for (const columnName of this.columnNames) {
const matchingColumns = fieldsForSearch.filter(c => columnName === c ||
columnName.match(c + '[ ][0-9]*$'));
if (matchingColumns && matchingColumns.length > 0) {
// do something...
}
}
这工作正常,但是,当我有一个巨大的数组时,它会花费很多时间,尤其是 .match
我怎样才能让它更快?使用 .test
或者 .startsWith
?
我过滤的 this.columnNames
可以有 Color
、Color 1
、Color 2
等值。这就是为什么我有这样的逻辑:
columnName.match(c + '[ ][0-9]*$'))
它也可以有这样的值:Age Range
、Age Range Minimum
、Age Range Maximum
。
我想要的是过滤名称和号码,所以在我上面的代码中,颜色,颜色 1... 通过,但 Age Range Minimum
没有。
示例输入:
['Color', 'Color 1', 'Color 2', 'Color 3', 'Age Range', 'Age Range Minimum', 'Age Range Maximum']
示例输出:
['Color', 'Color 1', 'Color 2', 'Color 3']
对于 OP 的用例,一种有效的方法是使用正则表达式,该正则表达式将匹配任何仅由空格分隔的非数字字符序列的字符串。像... /^(?:\D+\s+\D+)(?:\s+\D+)*$/
... Thus one matches exactly those strings, the OP wants to reject. A filter function then uses the negated return value of RegExp.prototype.test
...
const sampleInput = ['Color', 'Color 1', 'Color 2', 'Color 3', 'Age Range', 'Age Range Minimum', 'Age Range Maximum'];
const expectedResult = ['Color', 'Color 1', 'Color 2', 'Color 3'];
// matches any string wich is a sequence of
// whitespace separated non digit characters.
// see ... [https://regex101.com/r/6EBe7U/1/]
const regXWsSeparatedNonDigitSequence = (/^(?:\D+\s+\D+)(?:\s+\D+)*$/);
console.log(
sampleInput, ' =>',
sampleInput.filter(item =>
!regXWsSeparatedNonDigitSequence.test(item)
)
);
console.log(
'test passed ?',
sampleInput.filter(item =>
!regXWsSeparatedNonDigitSequence.test(item)
).join(',') === expectedResult.join(',')
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
顺便说一句……正则表达式的性能根本不是问题。
下一次过滤两次 70,000 个条目的测试确实证明了这一点(两次不到 7 毫秒)...
const regXWsSeparatedNonDigitSequence = (/^(?:\D+\s+\D+)(?:\s+\D+)*$/);
let testData = new Array(10_000);
let result;
// create an array of 70_000 string entries (10_000 x 7(string item count))
testData = testData
.fill(['Color', 'Color 1', 'Color 2', 'Color 3', 'Age Range', 'Age Range Minimum', 'Age Range Maximum'])
.flat(1);
// test with regex reference.
console.time("70,000 regX tests (reference) :: filter duration");
result = testData.filter(item =>
!regXWsSeparatedNonDigitSequence.test(item)
)
console.timeEnd("70,000 regX tests (reference) :: filter duration");
console.log('test passed ?.. ', (result.length === 40_000));
// test with regex literal.
console.time("70,000 regX tests (literal) :: filter duration");
result = testData.filter(item =>
!(/^(?:\D+\s+\D+)(?:\s+\D+)*$/).test(item)
)
console.timeEnd("70,000 regX tests (literal) :: filter duration");
console.log('test passed ?.. ', (result.length === 40_000));
.as-console-wrapper { min-height: 100%!important; top: 0; }