Как фильтровать массив на основе диапазона чисел?
У меня есть массив, который я фильтрую с помощью этой функции:
function filter(arr, criteria) {
return arr.filter(function(obj) {
return Object.keys(criteria).every(function(c) {
return !(criteria[c]) || obj[c] == criteria[c];
});
});
}
var arr = filter(arr, { dep: dv, arr: av, car: cv, epi: acv, dur: dv });
И у меня есть куча опций, которые пользователь может выбрать в выборе. Для продолжительности, вот что я имею:
<select name="duration" id="duration">
<option selected disabled hidden value="">-</option>
<option value="l1">Less than 1 hour</option>
<option value="1to3">1 to 3 hours</option>
<option value="3to6">3 to 6 hours</option>
<option value="6to10">6 to 10 hours</option>
<option value="m10">More than 10 hours</option>
</select>
Но этот фильтр основан на точных критериях. Я хочу отфильтровать числа с плавающей запятой в arr
, которые находятся между 1 и 3 или 6 и 10. Я также хочу иметь возможность запускать другие фильтры, которые вы видите там с помощью dep, arr, car, epi, dur. Есть ли способ сделать это?
Ответы
Ответ 1
Используйте array.filter
с обратным вызовом. В приведенном ниже коде используется словарь с элементами, соответствующими значениям опций.
var myArray = [1,2,3,3.1,Math.PI,4,4.3,6.1]; //sample array
//Dictionary from option values to functions (JS objects work like hashtables)
var options = {
"l1": function(a){return a.duration<1;},
"1to3": function(a){return a.duration>=1 && a.duration<3;},
"3to6": function(a){return a.duration>=3 && a.duration<=6;},
...
//When you need to filter the array, do it like so:
var myNewArray = myArray.filter(
options[ document.getElementById('duration').selectedOptions[0].value ]
);
Ответ 2
Предполагая, что я понял ваши потребности, что насчет этого:
jsFiddle
HTML:
<select name="duration" id="duration">
<option selected value="">Duration</option>
<option value="l1">Less than 1 hour</option>
<option value="1to3">1 to 3 hours</option>
<option value="3to6">3 to 6 hours</option>
<option value="6to10">6 to 10 hours</option>
<option value="m10">More than 10 hours</option>
</select>
<select name="acceleration" id="acceleration">
<option selected value="">Acceleration</option>
<option value="l2">Less than 2m/s²</option>
<option value="2to5">2 to 5m/s²</option>
<option value="5to10">5 to 10m/s²</option>
<option value="10to15">10 to 15m/s²</option>
<option value="m15">More than 15m/s²</option>
</select>
Данные:
var data = [
{duration:1.2, acceleration:5.7, name:'elt1'},
{duration:12, acceleration:1.5, name:'elt2'},
{duration:3, acceleration:7.8, name:'elt3'},
{duration:5.4789, acceleration:9.6597, name:'elt4'},
{duration:0.5, acceleration:12.154, name:'elt5'},
{duration:(15/7), acceleration:20.32, name:'elt6'},
{duration:9.81, acceleration:7.123, name:'elt7'},
{duration:10, acceleration:0.3265, name:'elt8'},
{duration:5, name:'elt9'} //never selected if there is an "acceleration" filter
];
JS:
var filterData = function(arr, criterias){
// First : parse the criterias
var realCriterias = {}, tmp;
var lessThan = /^l(.+)$/, between = /^(.+)to(.+)$/, moreThan = /^m(.+)$/;
for (var i in criterias){
if ("" === criterias[i]);
tmp = criterias[i].match(lessThan);
if (tmp) {
realCriterias[i] = {max:parseFloat(tmp[1])};
continue;
}
tmp = criterias[i].match(between);
if (tmp) {
realCriterias[i] = {min:parseFloat(tmp[1]), max:parseFloat(tmp[2])};
continue;
}
tmp = criterias[i].match(moreThan);
if (tmp) {
realCriterias[i] = {min:parseFloat(tmp[1])};
}
}
console.log('Real criterias', realCriterias);
// Then : apply them to arr
var results = [], elt, cri;
nextdata:
for (var i=0; i< arr.length; i++){
elt = arr[i];
for (var j in realCriterias){
if (!elt[j]) continue nextdata; // if criteria does not exits on elt, we break this loop and start again with next element
cri = realCriterias[j];
if ((undefined === cri.min && elt[j] >= cri.max) || //"less than" criteria and value is too big
(undefined === cri.max && elt[j] <= cri.min) || //"more than" criteria and value is too small
(elt[j] > cri.max || elt[j] < cri.min) // "between" criteria and value is not between min and max (included)
) {
continue nextdata; // we break this loop and start again with next element
}
}
results.push(elt);
}
return results;
}
var criterias = {
duration:$('#duration').val()||'',
acceleration:$('#acceleration').val()||''
};
var results = filterData(data , criterias);
Это довольно большая функция, но она полностью масштабируема. Вы можете использовать любые значения и любые необходимые вам критерии, если вы соблюдаете синтаксис l<max>
, <min>to<max>
и m<min>
в своих значениях <select>
.
Первая часть функции анализирует значения критериев, чтобы получить min или/и максимальное значение для каждого из них. Вторая часть - это сравнение каждого значения массива данных с ними.
Не стесняйтесь, если у вас есть какие-либо вопросы.