lodash / js: фильтрация значений в объекте на основе регулярных выражений и получение наибольшего по сравнению
для следующего json
[
{
"index": "xyz",
...
},
{
"index": "abc1234",
...
},
{
"index": "xyz",
...
},
{
"index": "abc5678",
...
}
...
Я хочу отфильтровать значения abc и xyz
значения отдельно.
я попробовал следующее, чтобы получить значения
var x = _.filter(jsonData, function (o) {
return /abc/i.test(o.index);
});
и он работал, чтобы дать отфильтрованных выходов.
теперь я хочу получить самый высокий из abc
значения, если есть значения abc123
, abc444
, abc999
тогда код должен вернуть abc999
.
Я могу повторить цикл с помощью lodash, но можно ли это сделать за один вызов - в том же самом, который отфильтровывается?
7 ответов
можно использовать Array.prototype.reduce()
, String.prototype.replace()
С RegExp
/\D+/
для сопоставления и удаления символов, которые не являются цифрами. Проверьте, если предыдущий номер часть строки меньше, чем текущий номер часть строки
var jsonData = [
{
"index": "xyz",
},
{
"index": "abc1234",
},
{
"index": "xyz",
},
{
"index": "abc5678",
},
{
"index": "abc1",
}];
var x = jsonData.reduce(function (o, prop) {
return /abc/i.test(prop.index)
? !o || +prop.index.replace(/\D+/, "") > +o.replace(/\D+/, "")
? prop.index
: o
: o
}, 0);
console.log(x);
Ниже приводится грубая и неудовлетворительная реализация:
//filter out matching objects for possible future use
var latest = "";
var matches = _.filter(jsonData, function (o) {
var ret = /abc/i.test(o.index);
if (ret) {
var digits = o.index.replace(/\D/g,'')
if (parseInt(digits) > latest) {
latest = digits;
latestIndex = o.index
console.log(latest+">>>latestIndex")
}
return true;
}
return false;
});
console.log("latestIndex->"+latest);
}
Если вы хотите найти высокие abc{SOME_NUMBER}
значение и фильтра в то же время, вы можете просто использовать регулярные итерации вместо _.filter
:
let jsonData = [{"index": "xyz"},{"index": "abc1234"}, {"index": "xyz"},{"index": "abc5678"}];
let max = Number.MIN_SAFE_INTEGER; // value for the max number at the end of "abc"
let item; // item containing the max abc${NUMBER} value
let filtered = []; // filtered array containing abc strings
jsonData.forEach((curr) => {
// filter test
if (/abc/i.test(curr.index)) {
filtered.push(curr);
// max value test
const [digits] = curr.index.match(/\d+/);
const test = parseInt(digits);
if (test > max) {
max = test;
item = curr;
}
}
});
console.log('Item:\n', item, '\n\n----\nFiltered:\n', filtered);
один из способов сделать это с помощью lodash-заменить filter
С maxBy
в коде.
конечно, у этого есть недостаток, что если в коллекции нет допустимых элементов, он будет произвольно возвращать недопустимый. Таким образом, после получения результата необходима дополнительная проверка действительности.
вот почему я извлек код проверки / фильтра в отдельной функции:
var jsonData = [{
"index": "xyz",
}, {
"index": "abc1234",
}, {
"index": "xyz",
}, {
"index": "abc5678",
}];
var isValid = function(o) {
return /abc/i.test(o.index);
};
var highest = _.maxBy(jsonData, isValid);
if (isValid(highest)) {
console.log('The max value is: ' + highest.index);
} else {
console.log('No valid value found!');
}
<script src="https://cdn.jsdelivr.net/lodash/4/lodash.min.js"></script>
и вот как это работает если есть нет допустимых элементов:
var jsonDataWithoutValidValues = [{
"index": "xyz",
}, {
"index": "xyz",
}];
var isValid = function(o) {
return /abc/i.test(o.index);
};
var highest = _.maxBy(jsonDataWithoutValidValues , isValid);
if (isValid(highest)) {
console.log('The max value is: ' + highest.index);
} else {
console.log('No valid value found!');
}
<script src="https://cdn.jsdelivr.net/lodash/4/lodash.min.js"></script>
это, вероятно, немного странно использовать в производстве, но я думал, что это достаточно интересно, чтобы поделиться.
Ну в этом случае вы можете просто использовать сортировку прототипа массива после того, как вы отфильтровали "abc", чтобы отсортировать их так, как вы хотите
var x = _.filter(jsonData, function (o) {
return /abc/i.test(o.index);
}).sort(function (a, b) {
if(a.index > b.index) return -1;
if(a.index < b.index) return 1;
return 0;
});
Если вы делаете правильный сортировка, вы можете получить наибольшее значение как
console.log(x[0].index)
Вы можете использовать один цикл с Array#reduce
и проверьте номер, если он существует.
var data = [{ index: "xyz" }, { index: "abc1234" }, { index: "xyz" }, { index: "abc5678" }],
getNumber = function (s) { return s.match(/^abc(\d+)/i)[1]; },
result = data.reduce(function (r, a) {
return a.index.match(/^abc\d/i) && (!r || getNumber(r.index) < getNumber(a.index)) ? a : r;
}, undefined);
console.log(result);
вот подход к цепочке lodash:
_(data)
.map('index')
.filter(_.method('match', /abc/))
.maxBy(_.flow(_.bindKey(/\d+/, 'exec'), _.first, _.toNumber));
на map()
и filter()
звонки получить список укусов с abc
в них. The maxBy()
вызов находит max, но мы должны составить функцию, чтобы сказать ей, что мы хотим сравнить ее численно. The flow()
функция действительно удобна для этого. Здесь мы говорим ему выполнить регулярное выражение, найти первый элемент результата и превратить его в число.