How to filter an associative array with another one?
function filter (a,f) {
console.log (a) ;
console.log (f) ;
//Using f as filter, How to get only these rows fom a ?
//{"XD_A":"XDR","XD_B_1":"38","XD_B_2":"PB"},
//{"XD_A":"XDR","XD_B_1":"38","XD_B_2":"PB"},
}
function test() {
var data = [{"XD_A":"XDL","XD_B_1":"38","XD_B_2":"PB"},
{"XD_A":"XDR","XD_B_1":"51","XD_B_2":"PB"},
{"XD_A":"XDL","XD_B_1":"58","XD_B_2":"PB"},
{"XD_A":"XDR","XD_B_1":"38","XD_B_2":"PB"},
{"XD_A":"XDL","XD_B_1":"76","XD_B_2":"PB"},
{"XD_A":"XDR","XD_B_1":"38","XD_B_2":"PB"}] ;
var filters =[{"XD_A":"XDR"},{"XD_B_1":"38"}] ;
filter (data,filters) ;
}
Thanks in advance,
best regards
Massimo
How to filter an associative array with another one?
function filter (a,f) {
console.log (a) ;
console.log (f) ;
//Using f as filter, How to get only these rows fom a ?
//{"XD_A":"XDR","XD_B_1":"38","XD_B_2":"PB"},
//{"XD_A":"XDR","XD_B_1":"38","XD_B_2":"PB"},
}
function test() {
var data = [{"XD_A":"XDL","XD_B_1":"38","XD_B_2":"PB"},
{"XD_A":"XDR","XD_B_1":"51","XD_B_2":"PB"},
{"XD_A":"XDL","XD_B_1":"58","XD_B_2":"PB"},
{"XD_A":"XDR","XD_B_1":"38","XD_B_2":"PB"},
{"XD_A":"XDL","XD_B_1":"76","XD_B_2":"PB"},
{"XD_A":"XDR","XD_B_1":"38","XD_B_2":"PB"}] ;
var filters =[{"XD_A":"XDR"},{"XD_B_1":"38"}] ;
filter (data,filters) ;
}
Thanks in advance,
best regards
Massimo
Share Improve this question edited Dec 5, 2016 at 6:31 CompSciFly 1703 silver badges19 bronze badges asked Dec 5, 2016 at 6:20 user7250540user7250540 2- 1 show us something you have tried? – kukkuz Commented Dec 5, 2016 at 6:21
- var rf = _.dropRightWhile(data, filters) ; but without success. Filters will change and "increase" dynamically – user7250540 Commented Dec 5, 2016 at 6:32
3 Answers
Reset to default 2
let data = [{"XD_A":"XDL","XD_B_1":"38","XD_B_2":"PB"},
{"XD_A":"XDR","XD_B_1":"51","XD_B_2":"PB"},
{"XD_A":"XDL","XD_B_1":"58","XD_B_2":"PB"},
{"XD_A":"XDR","XD_B_1":"38","XD_B_2":"One"},
{"XD_A":"XDL","XD_B_1":"76","XD_B_2":"PB"},
{"XD_A":"XDR","XD_B_1":"38","XD_B_2":"Two"}],
filters =[{"XD_A":"XDR"},{"XD_B_1":"38"}];
console.info(filter(data, filters));
function filter(d, f){
return data.filter(e => {
try{
f.forEach(o => {
Object.keys(o).forEach(key => {
if(e[key] !== o[key]) throw new 1;
});
});
return true;
}catch(e){
return false;
}
});
}
You could fiter the array without a try catch
block.
function filter(data, filter) {
return data.filter(function (d) {
return filter.every(function (f) {
var k = Object.keys(f)[0];
return d[k] === f[k];
});
});
}
var data = [{ "XD_A": "XDL", "XD_B_1": "38", "XD_B_2": "PB" }, { "XD_A": "XDR", "XD_B_1": "51", "XD_B_2": "PB" }, { "XD_A": "XDL", "XD_B_1": "58", "XD_B_2": "PB" }, { "XD_A": "XDR", "XD_B_1": "38", "XD_B_2": "PB" }, { "XD_A": "XDL", "XD_B_1": "76", "XD_B_2": "PB" }, { "XD_A": "XDR", "XD_B_1": "38", "XD_B_2": "PB" }],
filters = [{ "XD_A": "XDR" }, { "XD_B_1": "38" }];
console.log(filter(data, filters));
.as-console-wrapper { max-height: 100% !important; top: 0; }
ES6
function filter(data, filter) {
return data.filter(d => filter.every(f => (k => d[k] === f[k])(Object.keys(f)[0])));
}
var data = [{ "XD_A": "XDL", "XD_B_1": "38", "XD_B_2": "PB" }, { "XD_A": "XDR", "XD_B_1": "51", "XD_B_2": "PB" }, { "XD_A": "XDL", "XD_B_1": "58", "XD_B_2": "PB" }, { "XD_A": "XDR", "XD_B_1": "38", "XD_B_2": "PB" }, { "XD_A": "XDL", "XD_B_1": "76", "XD_B_2": "PB" }, { "XD_A": "XDR", "XD_B_1": "38", "XD_B_2": "PB" }],
filters = [{ "XD_A": "XDR" }, { "XD_B_1": "38" }];
console.log(filter(data, filters));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Associative array sorting, hmmm? I wanted to do this in a non-ES6 way (since I arrived at its solution in a few minutes; borrrrrring. JK I love you ES6!). I used your exact criteria from your own example.
Here's a non-library, non-ES6 way (just in case, just for fun) that includes some extra output results using the args: contains
, results
, strict
.
It also scales when filters need to increase/decrease. Note: it does not filter with multiple object properties as criteria, but instead exactly as you have posted: using multiple array items that are "associative arrays" (but is possible to change this, obviously).
This is my first post on SO, after many years using it (sorry.) Anyway, hope it works for you (FIDDLE HERE) and others, Massimo!
PS - If it's crap/buggy I'll try to find time to help you fix it.
/**
* _filterStrict only gives back data if both filter criteria are satisfied
* @param data {obj}
* filterList {arr}
* @returns bool
*/
var _filterStrict = function(data, filterList) {
var filterLength = filterList.length
// handy little truthy array
var strictMatchResults = []
for (var i = 0; i < filterLength; ++i) {
for (var prop in filterList[i]) {
// we need to match both the property and value
if (data.hasOwnProperty(prop) && data[prop] === filterList[i][prop]) {
strictMatchResults.push(true)
} else {
// no truthy for you! YOU CAN'T HANDLE THE TRUTH!
continue;
}
}
}
return strictMatchResults.length === filterLength ? true : false
}
/**
* _filterContains loose check; if data is found to be matching, it's a match.
* @param prop {str}
* val {str} // !could be extended to allow more types!
* filterList {arr}
* @returns bool
*/
var _filterContains = function(prop, val, filterList) {
var filterLength = filterList.length
var found = []
for (var i = 0; i < filterLength; ++i) {
// we need to match both the property and value
if (filterList[i].hasOwnProperty(prop) && filterList[i][prop] === val) {
return true
} else {
// "W-w-what? I have to go back to the expression, again? Ugh."
continue;
}
}
}
/**
* _filterChoose detects which filter to use via filterMode and selects
* the appropriate internal filter
* @param dataToCheck {obj}
* filterList {arr}
* filterMode {str}
* @returns arr
*/
var _filterChoose = function(dataToCheck, filterList, filterMode) {
var dataMatchesFilter = null
var initObjFlag = false
var filterLength = filterList.length
// run in "strict search" mode
if (filterMode === 'strict') {
return _filterStrict(dataToCheck, filterList) ? dataToCheck : null
}
// loop through slice of data
for (var prop in dataToCheck) {
var val = dataToCheck[prop]
// check against filter criteria
if (_filterContains(prop, val, filterList)) {
// only create the object literal once
if (initObjFlag === false) {
initObjFlag = true
dataMatchesFilter = {}
}
// only return the found results from the array
if (filterMode === 'results') {
dataMatchesFilter[prop] = val
}
// return the whole value if the data matches anywhere in the array
if (filterMode === 'contains' || filterMode === '' || filterMode === undefined) {
dataMatchesFilter = dataToCheck
}
}
}
return dataMatchesFilter
}
/**
* Filter "associative array" [{"str":"str"}]
* - Searches one level deep.
* - Filter Mode settings:
* * <contains|''|undefined> - loose search; returns whole object if even one * match is found. This is the default.
* * results - returns results only (does not include any other original values)
* * strict - returns a match only if *all* filter criteria are met
*
* @param data {arr}
* filterList {arr}
* filterMode {str} - possible values: '', contains', 'results', 'strict'
*/
var FilterAssoc = function(data, filterList, filterMode) {
// cache length for being nice to piler guy/gal
var dataLength = data.length
var filteredArray = []
// loop through array to access the object literals
for (var i = 0; i < dataLength; ++i) {
var filterRes = _filterChoose(data[i], filterList, filterMode)
// if results from our internal filter methods are NOT "null",
// then we need those results!
if (filterRes !== null) {
// build our results
filteredArray.push(filterRes)
}
}
return filteredArray
}
var filteredData = FilterAssoc(data, filters, 'strict')
console.log(filteredData)