#javascript #arrays
#javascript #массивы
Вопрос:
Я хочу сделать что-то вроде:
MyMap.set(['milk', 'eggs', 'flour'], 'ingredients');
MyMap.set(['red', 'green', 'blue'], 'colors');
console.log(MyMap.get(ELEMENT THAT INCLUDES eggs));
//expected: ingredients
Я перепробовал кучу вещей, таких как использование Array.has() и Array.includes(), но я просто не могу.
Я новичок здесь и в кодировании, поэтому извините, если я что-то перепутал или если решение абсурдно простое.
Комментарии:
1. Когда вы используете массив (или любой объект) в качестве ключа, вы можете получить значение, используя только точно такой же массив. Другой массив, который имеет те же значения, не будет работать.
2. Помимо этого, Map API не имеет возможности делать то, что вы хотите. Вам нужно было бы получить записи карты и выполнить итерацию по ним самостоятельно.
3. Уникальны ли элементы во всех массивах ключей? Существующий ответ неоптимален, но от этого зависит написание лучшего подхода. Было бы неплохо получить немного больше информации о вашем варианте использования, потому что это пахнет как проблема xy .
Ответ №1:
Map Api не поддерживает ничего подобного из коробки. Вот один из способов, которым вы можете это сделать.
let MyMap = new Map();
MyMap.set(['milk', 'eggs', 'flour'], 'ingredients');
MyMap.set(['red', 'green', 'blue'], 'colors');
let valuesWhoseKeyIncludeText = [];
MyMap.forEach((value, key) => {
if (key.includes('eggs')) {
valuesWhoseKeyIncludeText.push(value);
}
});
console.log(valuesWhoseKeyIncludeText);
//Above code returns Array of values whose key includes given text.
//So if you have multiple entries in Map whose key includes given text then you will get array of values as result. e.g
let MyMap2 = new Map();
MyMap2.set(['milk', 'eggs', 'flour'], 'ingredients');
MyMap2.set(['red', 'green', 'blue'], 'colors');
MyMap2.set(['red', 'eggs', 'flour'], 'ingredientsAndColors');
let valuesWhoseKeyIncludeText2 = [];
MyMap2.forEach((value, key) => {
if (key.includes('eggs')) {
valuesWhoseKeyIncludeText2.push(value);
}
});
console.log(valuesWhoseKeyIncludeText2);
Ответ №2:
Причина, по которой это кажется сложным, заключается в том, что структура не поддерживает ваш вариант использования. Ключ должен быть точным совпадением. Конечно, вы можете выгрузить все содержимое карты и выполнять итерации по нему каждый раз, когда вам нужно выполнить поиск с временной сложностью O(size of map * longest array key)
, что в значительной степени отбрасывает смысл структуры данных.
Лучшим подходом является построение карты путем перебора каждого элемента, который вы обычно связываете со значением, и выполнения нескольких сопоставлений с этим значением. Это сохраняет семантику ключ-значение и поддерживает O(1)
время поиска.
Другими словами, вместо того, чтобы пытаться (псевдокод):
{[key1, key2, key3]: val}
создайте это
{key1: val, key2: val, key3: val}
Недостатком этого подхода является то, что если вы устанавливаете значения, вам нужно будет делать это несколько раз для каждого возможного сопоставления ключей, но, похоже, это не ваш вариант использования здесь.
Вот минимальный, полный пример:
const rawPairData = [
[['milk', 'eggs', 'flour'], 'ingredients'],
[['red', 'green', 'blue'], 'colors'],
];
const map = new Map();
for (const [keys, val] of rawPairData) {
for (const key of keys) {
map.set(key, val);
}
}
console.log(map.get('milk'));
console.log(Object.fromEntries([...map]));
Теперь предполагается, что ключи уникальны во всех массивах. Если вам нужно поддерживать отображение одного ключа на несколько значений, следуйте стратегии, описанной выше, но создайте массивы значений. Еще раз, настройка сложна, но поиск выполняется быстро после одноразовых затрат, поэтому оптимизируйте то, что, как я полагаю, будет обычным случаем.
const rawPairData = [
[['milk', 'eggs', 'flour'], 'ingredients'],
[['milk', 'eggs', 'blue'], 'colors'],
];
const map = new Map();
for (const [keys, val] of rawPairData) {
for (const key of keys) {
map.set(key, [...(map.get(key) ?? []), val]);
}
}
console.log(map.get('eggs'));
console.log(Object.fromEntries([...map]));