Я создал библиотеку с именем PHPPowertools / DOM-Query , которая позволяет обходить HTML5 и XML-документы так же, как и с jQuery.
Под капотом используется symfony / DomCrawler для преобразования селекторов CSS в селектора XPath .
namespace PowerTools;
// Get file content
$htmlcode = file_get_contents('https://github.com');
// Define your DOMCrawler based on file string
$H = new DOM_Query($htmlcode);
// Define your DOMCrawler based on an existing DOM_Query instance
$H = new DOM_Query($H->select('body'));
// Passing a string (CSS selector)
$s = $H->select('div.foo');
// Passing an element object (DOM Element)
$s = $H->select($documentBody);
// Passing a DOM Query object
$s = $H->select( $H->select('p + p'));
// Select the body tag
$body = $H->select('body');
// Combine different classes as one selector to get all site blocks
$siteblocks = $body->select('.site-header, .masthead, .site-body, .site-footer');
// Nest your methods just like you would with jQuery
$siteblocks->select('button')->add('span')->addClass('icon icon-printer');
// Use a lambda function to set the text of all site blocks
$siteblocks->text(function( $i, $val) {
return $i . " - " . $val->attr('class');
});
// Append the following HTML to all site blocks
$siteblocks->append('');
// Use a descendant selector to select the site's footer
$sitefooter = $body->select('.site-footer > .site-center');
// Set some attributes for the site's footer
$sitefooter->attr(array('id' => 'aweeesome', 'data-val' => 'see'));
// Use a lambda function to set the attributes of all site blocks
$siteblocks->attr('data-val', function( $i, $val) {
return $i . " - " . $val->attr('class') . " - photo by Kelly Clark";
});
// Select the parent of the site's footer
$sitefooterparent = $sitefooter->parent();
// Remove the class of all i-tags within the site's footer's parent
$sitefooterparent->select('i')->removeAttr('class');
// Wrap the site's footer within two nex selectors
$sitefooter->wrap(' ');
[...]
Библиотека также включает собственный автозагрузчик с нулевой конфигурацией для совместимых с PSR-0 библиотек. Приведенный пример должен работать из коробки без какой-либо дополнительной настройки. Кроме того, вы можете использовать его с композитором.
Вы можете использовать параметр this
для функции filter (), чтобы избежать хранения вашего фильтра в глобальной переменной.
var filtered = [1, 2, 3, 4].filter(
function(e) {
return this.indexOf(e) < 0;
},
[2, 4]
);
var array = [1,2,3,4];
var anotherOne = [2,4];
var filteredArray = array.filter(myCallBack);
function myCallBack(el){
return anotherOne.indexOf(el) < 0;
}
В обратном вызове вы проверяете, находится ли каждое значение array
в anotherOne
https://jsfiddle.net/0tsyc1sx/
Если вы используете lodash.js
, используйте _.difference
filteredArray = _.difference(array, anotherOne);
Если у вас есть массив объектов:
var array = [{id :1, name :"test1"},{id :2, name :"test2"},{id :3, name :"test3"},{id :4, name :"test4"}];
var anotherOne = [{id :2, name :"test2"}, {id :4, name :"test4"}];
var filteredArray = array.filter(function(array_el){
return anotherOne.filter(function(anotherOne_el){
return anotherOne_el.id == array_el.id;
}).length == 0
});
/* Here's an example that uses (some) ES6 Javascript semantics to filter an object array by another object array. */
// x = full dataset
// y = filter dataset
let x = [
{"val": 1, "text": "a"},
{"val": 2, "text": "b"},
{"val": 3, "text": "c"},
{"val": 4, "text": "d"},
{"val": 5, "text": "e"}
],
y = [
{"val": 1, "text": "a"},
{"val": 4, "text": "d"}
];
// Use map to get a simple array of "val" values. Ex: [1,4]
let yFilter = y.map(itemY => { return itemY.val; });
// Use filter and "not" includes to filter the full dataset by the filter dataset's val.
let filteredX = x.filter(itemX => !yFilter.includes(itemX.val));
// Print the result.
console.log(filteredX);
В следующих примерах используется new Set()
для создания фильтрованного массива, который имеет только уникальные элементы:
Массив с примитивными типами данных: строка, число, логическое значение, значение null, undefined, symbol:
const a = [1, 2, 3, 4];
const b = [3, 4, 5];
const c = Array.from(new Set(a.concat(b)));
Массив с объектами как элементы:
const a = [{id:1}, {id: 2}, {id: 3}, {id: 4}];
const b = [{id: 3}, {id: 4}, {id: 5}];
const stringifyObject = o => JSON.stringify(o);
const parseString = s => JSON.parse(s);
const c = Array.from(new Set(a.concat(b).map(stringifyObject)), parseString);
Вы можете использовать фильтр, а затем для функции фильтра используйте сокращение фильтра, которое проверяет и возвращает true, когда находит совпадение, а затем инвертирует по возврату (!). Функция фильтра вызывается один раз для каждого элемента массива. Вы не выполняете сравнение каких-либо элементов в функции в своем сообщении.
var a1 = [1, 2, 3, 4],
a2 = [2, 3];
var filtered = a1.filter(function(x) {
return !a2.reduce(function(y, z) {
return x == y || x == z || y == true;
})
});
document.write(filtered);
function arr(arr1,arr2){
function filt(value){
return arr2.indexOf(value) === -1;
}
return arr1.filter(filt)
}
document.getElementById("p").innerHTML = arr([1,2,3,4],[2,4])
<p id="p"></p>
Все вышеперечисленные решения «работают», но менее оптимальны для производительности и все они подходят к проблеме таким же образом, что и линейный поиск всех записей в каждой точке с помощью Array.prototype.indexOf или Array.prototype.includes . Более быстрое решение (гораздо быстрее, чем бинарный поиск в большинстве случаев) - это сортировка массивов и проскальзывание вперед, как вы видите ниже. Однако один недостаток заключается в том, что для этого требуется, чтобы все записи в массиве были числами или строками. Однако, однако, бинарный поиск может в некоторых редких случаях быть быстрее, чем прогрессивный линейный поиск. Эти случаи возникают из-за того, что мой прогрессивный линейный поиск имеет сложность O (2n1 + n2) (только O (n1 + n2) в более быстрой версии C / C ++ ) (где n1 - искомый массив, а n2 - массив фильтров), тогда как бинарный поиск имеет сложность O (n1ceil (log2n2)) (ceil = round up - ceil ing), и, наконец, поиск indexOf имеет весьма переменную сложность между O (n1) и O (n1n2) , усредняя по O (n1ceil (n2 ÷ 2)) . Таким образом, indexOf будет только самым быстрым, в среднем, в случаях (n1, n2) , равных {1,2} , {1,3} или {x, 1 | x∈N} . Тем не менее, это все еще не идеальное представление современного оборудования. IndexOf оптимизирован в максимально возможной степени в большинстве современных браузеров, что делает его очень подверженным законам предсказания ветвей . Таким образом, если мы сделаем такое же предположение на indexOf, как и в случае с прогрессивным линейным и двоичным поиском, - чтобы массив был предварительно настроен, то, согласно статистическим данным, перечисленным в ссылке, мы можем ожидать примерно 6-кратное ускорение для IndexOf, смещение его сложности между O (n1 ÷ 6) и O (n1n2) , усреднение по O (n1ceil (n27 ÷ 12)) , Наконец, обратите внимание, что приведенное ниже решение никогда не будет работать с объектами, потому что невозможно получить внутренний указатель объекта (для численного сравнения) в javascript.
function sortAnyArray(a,b) { return a>b ? 1 : (a===b ? 0 : -1); }
function sortIntArray(a,b) { return a - b; }
var Math_clz32 = Math.clz32;
function filterArrayByAnotherArray(searchArray, filterArray, isInteger = false, i = 0) {
if (isInteger) { // if all entries in both arrays are integers
searchArray.sort(sortIntArray);
filterArray.sort(sortIntArray);
} else {
searchArray.sort(sortAnyArray);
filterArray.sort(sortAnyArray);
}
var searchArrayLen = searchArray.length, filterArrayLen = filterArray.length;
var progressiveLinearComplexity = ((searchArrayLen<<1) + filterArrayLen)>>>0
var binarySearchComplexity= (searchArrayLen * (32-Math_clz32(filterArrayLen-1)))>>>0;
// After computing the complexity, we can predict which algorithm will be the fastest
if (progressiveLinearComplexity < binarySearchComplexity) {
// Progressive Linear Search
return searchArray.filter(function(currentValue){
while (filterArray[i] < currentValue) ++i;
// +undefined = NaN, which is always false for <, avoiding an infinite loop
return filterArray[i] !== currentValue;
});
} else {
// Binary Search
return searchArray.filter(function(currentValue) {
var lo = -1, hi = filterArrayLen;
while (1 + lo !== hi) {
const mi = (hi + lo) >> 1;
if (currentValue <= filterArray[mi]) hi = mi; else lo = mi;
}
return filterArray[hi] !== currentValue;
});
}
}
Чтобы доказать разницу в скорости, давайте рассмотрим некоторые JSPerfs. Для фильтрации массива из 16 элементов бинарный поиск примерно на 17% быстрее, чем indexOf, тогда как filterArrayByAnotherArray примерно на 93% быстрее, чем indexOf. Для фильтрации массива из 256 элементов бинарный поиск примерно на 291% быстрее, чем indexOf, тогда как filterArrayByAnotherArray примерно на 353% быстрее, чем indexOf. Для фильтрации массива из 4096 элементов бинарный поиск примерно на 2655% быстрее, чем indexOf, тогда как filterArrayByAnotherArray примерно на 4627% быстрее, чем indexOf.
Вы можете написать общую функцию filterByIndex () и использовать вывод типа в TS, чтобы сохранить проблему с функцией обратного вызова:
, допустим, у вас есть ваш массив [1,2,3,4 ], которые вы хотите отфильтровать () с индексами, указанными в массиве [2,4].
var filtered = [1,2,3,4,].filter(byIndex(element => element, [2,4]))
функция byIndex ожидает функцию элемента и массив и выглядит следующим образом:
РезультатомbyIndex = (getter: (e:number) => number, arr: number[]) => (x: number) => {
var i = getter(x);
return arr.indexOf(i);
}
является
filtered = [1,3]
Вы можете настроить функцию фильтра для итерации по «фильтру».
var arr = [1, 2, 3 ,4 ,5, 6, 7];
var filter = [4, 5, 6];
var filtered = arr.filter(
function(val) {
for (var i = 0; i < filter.length; i++) {
if (val == filter[i]) {
return false;
}
}
return true;
}
);
Я бы сделал следующее:
var arr = [1,2,3,4],
brr = [2,4],
res = arr.filter(f => !brr.includes(f));
console.log(res);
Лучшее описание функции filter
- https://developer.mozilla.org/pl/docs/Web/JavaScript/Referencje/Obiekty/Array/filter
] Вы должны просто выполнить функцию:
function conditionFun(element, index, array) {
return element >= 10;
}
filtered = [12, 5, 8, 130, 44].filter(conditionFun);
И вы не можете получить доступ к значению переменной до его назначения
Более гибкий фильтрующий массив из другого массива, который содержит свойства объекта
function filterFn(array, diffArray, prop, propDiff) {
diffArray = !propDiff ? diffArray : diffArray.map(d => d[propDiff])
this.fn = f => diffArray.indexOf(f) === -1
if (prop) {
return array.map(r => r[prop]).filter(this.fn)
} else {
return array.filter(this.fn)
}
}
//You can use it like this;
var arr = [];
for (var i = 0; i < 10; i++) {
var obj = {}
obj.index = i
obj.value = Math.pow(2, i)
arr.push(obj)
}
var arr2 = [1, 2, 3, 4, 5]
var sec = [{t:2}, {t:99}, {t:256}, {t:4096}]
var log = console.log.bind(console)
var filtered = filterFn(arr, sec, 'value', 't')
var filtered2 = filterFn(arr2, sec, null, 't')
log(filtered, filtered2)