Reputation: 6015
For the following json
[
{
"index": "xyz",
...
},
{
"index": "abc1234",
...
},
{
"index": "xyz",
...
},
{
"index": "abc5678",
...
}
...
I want to filter out abc values and xyz
values separately.
I tried the following to get values
var x = _.filter(jsonData, function (o) {
return /abc/i.test(o.index);
});
and it worked to give the filtered outputs.
Now i want to get the highest of abc
values that is if there values abc123
, abc444
, abc999
then the code should return abc999
.
I can loop over again using lodash but could this be done in a single call - within the same one that filters out?
Upvotes: 6
Views: 1620
Reputation: 11211
Here's a lodash chaining approach:
_(data)
.map('index')
.filter(_.method('match', /abc/))
.maxBy(_.flow(_.bindKey(/\d+/, 'exec'), _.first, _.toNumber));
The map()
and filter()
calls get you a list of stings with abc
in them. The maxBy()
call finds the max, but we have to compose a function to tell it that we want to compare it numerically. The flow()
function is really handy for this. Here, we're telling it to execute the regular expression, find the first element of the result, and turn that into a number.
Upvotes: 1
Reputation: 386680
You could use a single loop with Array#reduce
and check the number, if exists.
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);
Upvotes: 1
Reputation: 1
You can use Array.prototype.reduce()
, String.prototype.replace()
with RegExp
/\D+/
to match and remove characters that are not digits. Check if previous number portion of string is less than current number portion of string
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);
Upvotes: 4
Reputation: 348
Well in this case you can just use Array prototype sort after you have filtered out the 'abc' to sort them the way you want
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;
});
if you do the sorting correct you can get the highest value like
console.log(x[0].index)
Upvotes: 1
Reputation: 40566
One way to do it using lodash is by replacing filter
with maxBy
in your code.
Of course, this has the downside that if no valid elements exist in the collection, it'll arbitrarily return an invalid one. So, after getting the result, an extra validity check is needed.
This is why I have extracted the validation/filter code in a separate function:
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>
And here's how it works if there are no valid elements:
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>
This is a probably a bit weird to use in production, but I thought it was interesting enough to share.
Upvotes: 2
Reputation: 35491
If you want to find the highest abc{SOME_NUMBER}
value and filter at the same time, you can just use regular iteration instead of _.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);
Upvotes: 2
Reputation: 6015
Following is a crude and unsatisfactory implementation:
//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);
}
Upvotes: 2