Как найти элементы массива в другом массиве

If you don’t need type coercion (because of the use of indexOf), you could try something like the following:

var arr = [1, 2, 3];
var check = [3, 4];

var found = false;
for (var i = 0; i < check.length; i++) {
    if (arr.indexOf(check[i]) > -1) {
        found = true;
        break;
    }
}
console.log(found);

Where arr contains the target items. At the end, found will show if the second array had at least one match against the target.

Of course, you can swap out numbers for anything you want to use — strings are fine, like your example.

And in my specific example, the result should be true because the second array’s 3 exists in the target.


UPDATE:

Here’s how I’d organize it into a function (with some minor changes from before):

var anyMatchInArray = (function () {
    "use strict";

    var targetArray, func;

    targetArray = ["apple", "banana", "orange"];
    func = function (checkerArray) {
        var found = false;
        for (var i = 0, j = checkerArray.length; !found && i < j; i++) {
            if (targetArray.indexOf(checkerArray[i]) > -1) {
                found = true;
            }
        }
        return found;
    };

    return func;
}());

DEMO: http://jsfiddle.net/u8Bzt/

In this case, the function could be modified to have targetArray be passed in as an argument instead of hardcoded in the closure.


UPDATE2:

While my solution above may work and be (hopefully more) readable, I believe the «better» way to handle the concept I described is to do something a little differently. The «problem» with the above solution is that the indexOf inside the loop causes the target array to be looped over completely for every item in the other array. This can easily be «fixed» by using a «lookup» (a map…a JavaScript object literal). This allows two simple loops, over each array. Here’s an example:

var anyMatchInArray = function (target, toMatch) {
    "use strict";

    var found, targetMap, i, j, cur;

    found = false;
    targetMap = {};

    // Put all values in the `target` array into a map, where
    //  the keys are the values from the array
    for (i = 0, j = target.length; i < j; i++) {
        cur = target[i];
        targetMap[cur] = true;
    }

    // Loop over all items in the `toMatch` array and see if any of
    //  their values are in the map from before
    for (i = 0, j = toMatch.length; !found && (i < j); i++) {
        cur = toMatch[i];
        found = !!targetMap[cur];
        // If found, `targetMap[cur]` will return true, otherwise it
        //  will return `undefined`...that's what the `!!` is for
    }

    return found;
};

DEMO: http://jsfiddle.net/5Lv9v/

The downside to this solution is that only numbers and strings (and booleans) can be used (correctly), because the values are (implicitly) converted to strings and set as the keys to the lookup map. This isn’t exactly good/possible/easily done for non-literal values.

Here’s a way I am doing it after researching it for a while. I wanted to make a Laravel API endpoint that checks if a field is «in use», so the important information is: 1) which DB table? 2) what DB column? and 3) is there a value in that column that matches the search terms?

Knowing this, we can construct our associative array:

$SEARCHABLE_TABLE_COLUMNS = [
    'users' => [ 'email' ],
];

Then, we can set our values that we will check:

$table = 'users';
$column = 'email';
$value = 'alice@bob.com';

Then, we can use array_key_exists() and in_array() with eachother to execute a one, two step combo and then act upon the truthy condition:

// step 1: check if 'users' exists as a key in `$SEARCHABLE_TABLE_COLUMNS`
if (array_key_exists($table, $SEARCHABLE_TABLE_COLUMNS)) {

    // step 2: check if 'email' is in the array: $SEARCHABLE_TABLE_COLUMNS[$table]
    if (in_array($column, $SEARCHABLE_TABLE_COLUMNS[$table])) {

        // if table and column are allowed, return Boolean if value already exists
        // this will either return the first matching record or null
        $exists = DB::table($table)->where($column, '=', $value)->first();

        if ($exists) return response()->json([ 'in_use' => true ], 200);
        return response()->json([ 'in_use' => false ], 200);
    }

    // if $column isn't in $SEARCHABLE_TABLE_COLUMNS[$table],
    // then we need to tell the user we can't proceed with their request
    return response()->json([ 'error' => 'Illegal column name: '.$column ], 400);
}

// if $table isn't a key in $SEARCHABLE_TABLE_COLUMNS,
// then we need to tell the user we can't proceed with their request
return response()->json([ 'error' => 'Illegal table name: '.$table ], 400);

I apologize for the Laravel-specific PHP code, but I will leave it because I think you can read it as pseudo-code. The important part is the two if statements that are executed synchronously.

array_key_exists() and in_array() are PHP functions.

source:

  • https://php.net/manual/en/function.array-key-exists.php

  • https://php.net/manual/en/function.in-array.php

The nice thing about the algorithm that I showed above is that you can make a REST endpoint such as GET /in-use/{table}/{column}/{value} (where table, column, and value are variables).

You could have:

$SEARCHABLE_TABLE_COLUMNS = [
    'accounts' => [ 'account_name', 'phone', 'business_email' ],
    'users' => [ 'email' ],
];

and then you could make GET requests such as:

GET /in-use/accounts/account_name/Bob's Drywall (you may need to uri encode the last part, but usually not)

GET /in-use/accounts/phone/888-555-1337

GET /in-use/users/email/alice@bob.com

Notice also that no one can do:

GET /in-use/users/password/dogmeat1337 because password is not listed in your list of allowed columns for user.

Good luck on your journey.

In JavaScript, you can check if every element of the first array exists in the second array, in the following ways:

  • Using Array.prototype.every();
  • Using a Loop.

Using Array.prototype.every()

To check if every element of the first array exists in the second array, you can do the following:

  1. Use Array.prototype.every() method to check whether all elements in an array pass the test implemented by the provided function;
  2. Use Array.prototype.includes() (or Array.prototype.indexOf() in the callback of Array.prototype.every() to check if the current element of first array exists in the second array.

For example, you can implement this in the following way:

// ES7+
const arr1 = [ 1, 2, 3 ];
const arr2 = [ 3, 5, 4, 2, 7, 0, 1, 10 ];

const hasAllElems = arr1.every(elem => arr2.includes(elem));

console.log(hasAllElems); // true

If one or more elements do not exist in the second array, then false is returned (as you can see in the example below):

// ES7+
const arr1 = [ 1, 2, 16 ];
const arr2 = [ 3, 5, 4, 2, 7, 0, 1, 10 ];

const hasAllElems = arr1.every(elem => arr2.includes(elem));

console.log(hasAllElems); // false

If you are unable to support ES7, then you can achieve the same in ES5 using Array.prototype.indexOf() (instead of Array.prototype.includes()), for example, like so:

// ES5+
const arr1 = [ 1, 2, 3 ];
const arr2 = [ 3, 5, 4, 2, 7, 0, 1, 10 ];

const hasAllElems = arr1.every(function (elem) {
    return arr2.indexOf(elem) > -1;
});

console.log(hasAllElems); // true

If you are able to support ES6, then you can rewrite the callback to Array.prototype.every() as an arrow function to make it more compact.

Using a Loop

To check if every element of the first array exists in the second array, you can do the following:

  1. Use a loop (such as a for loop) and iterate over the first array;
  2. In each iteration, use Array.prototype.indexOf() (or Array.prototype.includes()) to check if the current element of first array exists in the second array;
  3. Return true from the callback if all elements of first array exist in the second array, otherwise, return false.

For example, you can implement this using a for loop and Array.prototype.indexOf() in the following way:

const arr1 = [ 1, 2, 3 ];
const arr2 = [ 3, 5, 4, 2, 7, 0, 1, 10 ];

let hasAllElems = true;

for (let i = 0; i < arr1.length; i++){
    if (arr2.indexOf(arr1[i]) === -1) {
        hasAllElems = false;
        break;
    }
}

console.log(hasAllElems); // true

This can be especially useful if you are unable to support a minimum ES5 as with the other method.

Using the same code, you can see that if one or more elements do not exist in the second array, then false is returned:

const arr1 = [ 1, 2, 16 ];
const arr2 = [ 3, 5, 4, 2, 7, 0, 1, 10 ];

let hasAllElems = true;

for (let i = 0; i < arr1.length; i++){
    if (arr2.indexOf(arr1[i]) === -1) {
        hasAllElems = false;
        break;
    }
}

console.log(hasAllElems); // false

You can also create a function for this like so:

function arrayContainsAll(needle, haystack) {
    for (let i = 0; i < needle.length; i++){
        if (haystack.indexOf(needle[i]) === -1) {
            return false;
        }
    }

    return true;
}

const result1 = arrayContainsAll([ 1, 2, 3 ], [ 3, 5, 4, 2, 7, 0, 1, 10 ]);
const result2 = arrayContainsAll([ 1, 2, 16 ], [ 3, 5, 4, 2, 7, 0, 1, 10 ]);

console.log(result1); // true
console.log(result2); // false

Hope you found this post useful. It was published 26 Dec, 2020 (and was last revised 02 Feb, 2023). Please show your love and support by sharing this post.

Если @egor_nullptr вас понял правильно, и вам нужно проверить, что массив b хотя бы в одном экзепляре содержит каждый элемент массива a, то предлагаю такое решение:

Array.prototype.hasAll = function(a) {
    var hash = this.reduce(function(acc, i) { acc[i] = true; return acc; }, {});
    return a.every(function(i) { return i in hash; });
};

По сравнению с решением @egor_nullptr оно асимптотически быстрее: O(n + m) против O(n * m), где n, m — размеры массивов a, b. При n = m = 100 000 на моей машине мой вариант отрабатывает быстрее в 200 раз. Тестировал так.

Знаете, каков мой опыт разработки на JavaScript? Я программирую на нём 40 минут, в обнимку с JavaScript Reference от Mozilla. Мой основной язык — C++. А вам очень советую добраться-таки до какой-нибудь книжки по алгоритмам и структурам данных (например, до «Introduction to Algorithms». Она есть на русском, лучший перевод, на мой взгляд, от МЦНМО). Это полезно, уверяю вас.

Эту задачу можно понять несколькими смыслами:

  1. Мы в принципе хотим понять существует ли массив с квадратными скобками в основном массиве
  2. Мы хотим понять, есть ли похожий массив в основном массиве (с теми же элементами и их значениями)

В этой публикации мы рассмотрим эти два варианта трактования вопроса. Начнём с простого.

Есть ли какой-то массив в основном массиве? Он существует в виде значения элемента основного массива?

Есть основной массив с одним объектом, одним массивом, числами и строками:

var massiv = [1, 2, 3, {a:"a"}, [777], 4, 5, "efim360.ru", "javascript"]

Мы будем проверять существование какого-либо массива в основном массиве при помощи метода filter(). Внутрь метода filter() мы будем передавать анонимную функцию, которая будет возвращать нам true или false по заданному условию. Если будет true, то элемент попадёт в новый массив (отфильтрованный), если false, то не попадёт.

Т. к. мы имеем дело с прототипами классов, то условие сравнения будет определяться при помощи «имени конструктора«, в котором этот элемент был создан. В качестве цели будет выбран класс Array, а его имя конструктора будет строкой «Array«. Не перепутайте, а то не получится. Мы сравниваем строки!

massiv.filter(i => i.constructor.name == "Array")

Метод filter нашёл массив в массиве - JavaScript

Метод filter нашёл массив в массиве — JavaScript

Мы вызвали filter() и в ответ получили новый массив (отфильтрованный) с одним элементом. Это как раз то, что мы искали. Мы отловили в основном массиве какой-то массив.

Мы имеем новый массив (отфильтрованный) длиной 1. Если бы в нашем основном массиве небыло бы массивов, тогда фильтр вернул бы нам массив нулевой длины. Вот это и будет нашим условием существования какого либо объекта в массиве:

(massiv.filter(i => i.constructor.name == "Array").length > 0)

Условие существования массива в массиве - JavaScript

Условие существования массива в массиве — JavaScript

Получили ИСТИНУ (TRUE) значит в основном массиве есть массив.

Справка

Мы всегда можем распознать объект по его принадлежности к классу. В нашем случае:

  • фигурные скобки принадлежат классу Object,
  • квадратные скобки принадлежат классу Array,
  • числа принадлежат классу Number
  • строки принадлежат классу String

Давайте убедимся, что это так. Мы будем получать класс каждого элемента. То есть мы будем получать название конструктора, в котором был создан данный элемент массива.

massiv.map(i=>[i, i.constructor.name])

Получили имена конструкторов значений элементов массива и сопоставили - JavaScript

Получили имена конструкторов значений элементов массива и сопоставили — JavaScript

Есть ли похожий массив в массиве?

На эту тему можно спорить долго. «Одинаковость» массивов я буду определять по Наборам элементов. Если наборы совпадают — значит элементы равны (очень похожи друг на друга). Вы можете придумать свой вариант схожести массивов.

Есть массив:

var massiv = [[1,2,3], [3,2,1], [1,2,3,4], 4, 5, 6, "efim360.ru", "javascript", true]

Именно в таком виде, где порядок значений внутренних массивов отличается.

Предположим, что мы хотим узнать существование массива [3,2,1] в основном массиве. Есть ли похожий? Как это сделать?

Давайте с «подводных камней». Как вам такое условие?

Неравенство идентичных массивов - JavaScript

Неравенство идентичных массивов — JavaScript

Для кого-то это будет шок! Это значит, что мы не можем сравнивать массивы «в тупую» как они есть. Что делать?

Нужно привести массивы к строке и сравнивать строки. Поможет нам в этом конструктор JSON и его метод stringify(). В чём его слабость? В том, что он НЕ сортирует ключи перед упаковкой в строку. 🙂

Смотрим как это работает:

JSON.stringify([3,2,1])
"[3,2,1]"

JSON.stringify([1,2,3])
"[1,2,3]"

JSON.stringify([3,2,1]) == JSON.stringify([1,2,3])
false

JSON.stringify не сортирует элементы массивов - JavaScript

JSON.stringify не сортирует элементы массивов — JavaScript

Итоговые строки не равны — false

Сейчас нам нужна функция, которая умеет сортировать значения в массивах, до их передачи в stringify()

Мы можем сделать так:

  1. Создаём новый набор Set
  2. Конвертируем набор в массив
  3. Сортируем массив
  4. Переводим массив в строку
  5. Сравниваем строки

Поехали

JSON.stringify(Array.from(new Set([3,2,1])).sort())
"[1,2,3]"

JSON.stringify(Array.from(new Set([1,2,3])).sort())
"[1,2,3]"

JSON.stringify(Array.from(new Set([3,2,1])).sort()) == JSON.stringify(Array.from(new Set([1,2,3])).sort())
true

Сравнили два массива из набора - получили true - JavaScript

Сравнили два массива из набора — получили true — JavaScript

Мы научились сравнивать массивы и теперь можем вернуться к нашему основному массиву и проверить есть ли в нём такой массив или нет.

Будем использовать тот же самый filter()

massiv.filter(i=>JSON.stringify(Array.from(new Set(i)).sort()) == JSON.stringify(Array.from(new Set([3,2,1])).sort())  )

В таком виде команда может не сработать, т. к. попытка приведения неитерируемого объекта к Набору вызовет ошибку:

Ошибка приведения к Набору - JavaScript

Ошибка приведения к Набору — JavaScript

new Set(4) — вызовет ошибку. По этой причине нам нужна двойная фильтрация!

Итог

Первая фильтрация:

massiv.filter(i => i.constructor.name == "Array")

Отловили все массивы в основном массиве

Первая фильтрация для отлова массивов - JavaScript

Первая фильтрация для отлова массивов — JavaScript

Вторая фильтрация:

massiv.filter( i=>i.constructor.name == "Array" ).filter( i => JSON.stringify(Array.from(new Set(i)).sort()) == JSON.stringify(Array.from(new Set([3,2,1])).sort())  )

Вторая фильтрация для приведения массивов к строкам - JavaScript

Вторая фильтрация для приведения массивов к строкам — JavaScript

Отыскали похожий массив на наш. Даже два похожих. Хочу обратить ваше внимание, что массив [1,2,3,4] был исключён из фильтрации по причине наличия в нём значения «4».

Длина отфильтрованного массива больше «0» (нуля), значит искомый массив встречается в основном массиве. Это и есть условие:

massiv.filter( i=>i.constructor.name == "Array" ).filter( i => JSON.stringify(Array.from(new Set(i)).sort()) == JSON.stringify(Array.from(new Set([3, 2, 1])).sort())  ).length > 0
true

Задача выполнена!

Информационные ссылки

JavaScript | Равенство объектов

JavaScript | Как узнать экземпляром какого класса является объект?

Стандарт ECMAScript — Раздел «25.5 The JSON Object» — https://tc39.es/ecma262/#sec-json-object

Понравилась статья? Поделить с друзьями:
  • Как найти бога кузю
  • Как найти предыдущие вкладки
  • Как найти угол в треугольнике зная два
  • Как найти мотив произведения
  • Как исправить задохнувшееся сало