Итак, я хочу начать с того, что вам определенно есть чему поучиться прямо сейчас. Всегда полезно сделать несколько попыток, выяснить свой подход, а затем объяснить его любыми кусками кода, которые вы можете предоставить, работает ли он или нет. Ваш вопрос здесь не самый ясный, поэтому я приведу свой пример того, как я его интерпретировал. Я также собираюсь объяснить в несколько нисходящем подходе, так что это немного читается.
Используя введенные вами данные и описание, давайте работать над функция, которая принимает имя режима и возвращает true, если strArr
содержит все координаты, которые этот режим имеет в coArr
. Чтобы прояснить условия, скажем, что если эта функция возвращает true
, мы скажем, что данный режим покрыт на strArr
. Надеюсь, ты со мной до сих пор.
const isModeCovered = modeName => {
let mode = coArr.find(x => x.name == modeName);
let modeCoordinates = strArr.filter(x => x.name == modeName);
return mode.isCoveredBy(modeCoordinates);
};
function isModeCovered(modeName) {
let mode = coArr.find(function(x) {
return x.name == modeName;
});
let modeCoordinates = strArr.filter(function(x) {
return x.name == modeName;
});
return mode.isCoveredBy(modeCoordinates);
}
Здесь у нас есть функция, которую я написал для этого. Как вы можете видеть, я написал эту функцию дважды: один раз, используя функции стрелок и один раз используя "нормальные" функции. Я не собираюсь углубляться в go, чтобы узнать, что такое функция Arrow в Javascript, и вы увидите, что в остальной части этого примера они будут использованы. Если вам необходимо ознакомиться с ними сейчас, самое время это сделать, но вы также можете понять их, просто сравнив две функции выше. В любом случае, давайте продолжим и посмотрим, что на самом деле делает эта функция.
let mode = coArr.find(x => x.name == modeName);
Здесь мы используем функцию find
, чтобы найти первый элемент в coArr
имя которого совпадает с именем данного режима. Как видно из ссылки, find
ищет каждый элемент Array
, над которым он выполняется, и возвращает первый элемент, который возвращает заданный обратный вызов. Обратный вызов, который мы ему дали , не будет работать . Это потому, что предполагается, что каждый элемент coArr
является объектом, который имеет name
. Следующая строка, где мы фильтруем strArr
, также будет не работать по аналогичной причине.
Почему я это сделал?
Я сделал это, потому что данные в том виде, в каком они были предоставлены, - если быть тупым - головная боль. Вы можете абсолютно решить эту проблему без изменения данных, но есть много причин, по которым я предпочитаю это, я объясню позже. Итак, мы собираемся предположить, что мы взяли данные и проанализировали в более удобные для использования формы:
const modes = coArr.map(x => new Mode(x));
const allModeCoordinates = strArr.map(x => new ModeCoordinate(x));
const isModeCovered = modeName => {
let mode = modes.find(x => x.name == modeName);
let modeCoordinates = allModeCoordinates.filter(x => x.name == modeName);
return mode.isCoveredBy(modeCoordinates);
};
Хорошо, вот немного измененный код. Мы видим, что сопоставляет coArr
с новым массивом объекта с именами Mode
и сопоставляет strArr
с новым массивом объекта называется ModeCoordinate
. Мы можем беспокоиться о , как конструктор для этих объектов обрабатывает это позже, но для ясности здесь кратко дано представление о том, как эти объекты выглядят (в псевдо-JS это не скомпилируется) :
class Coordinate {
int x,
int y
}
class Mode {
string name,
Coordinate[] coordinates // an Array of Coordinates
}
class ModeCoordinate {
string name,
Coordinate coordinate
}
Если наши данные находятся в Array
с Mode
с и ModeCoordinate
с, мы можем легко искать по их имени и находить их координаты. Как только мы можем легко это сделать, большая часть работы для нас сделана, и нам просто нужно определить детали логики c за последней строкой функции:
return mode.isCoveredBy(modeCoordinates);
Давайте добавим эту функцию, isCoveredBy
до Mode
класса:
class Mode {
string name,
Coordinate[] coordinates
isCoveredBy(modeCoordinates) {
for (const coordinate of this.coordinates) {
if (!!!modeCoordinates.find(c => c.coordinate.equals(coordinate)))
return false;
}
return true;
}
}
Это короткий метод, но давайте быстро go пройдемся по нему. Мы используем от for of
до l oop через каждые Coordinate
в Mode
в coordinates
. Затем мы используем if
, чтобы проверить, можем ли мы найти, что Coordinate
в Array
из заданных Coordinate
с (которые, если вы помните, взяты из strArr
, которые имеют то же имя режима, что и Mode
мы находимся). Если мы не можем найти его, мы немедленно возвращаем false
, потому что для того, чтобы режим был "покрыт", мы заявили, что каждая отдельная координата должна также существовать в strArr
. Если он не возвратил false
в любой момент, мы возвращаем true
в конце l oop, потому что это означает, что они все были найдены.
Есть вероятность, что эта строка, условие if
, может сбить с толку:
!!!modeCoordinates.find(c => c.coordinate.equals(coordinate))
Мы можем кратко разобрать это. modeCoordinates.find(c => c.coordinate.equals(coordinate))
принимает modeCoordinates
, который, если вы помните, является ModeCoordinate
Array
, в который мы сопоставили все наши strArr
элементы и отфильтровали его по имени режима Mode
, в котором мы находимся, и пытаясь найти тот, который имеет Coordinate
, равный координате нашей текущей итерации l oop. Возвращает элемент, если он найден, или ложь, если не найден. !!!
перед ним является комбинацией обычного оператора !
или нет и оператора !!
, который переводит возвращаемое значение в логическое значение.
Итак, теперь мы знаем, что нам нужно проанализировать данные в наших более хороших типах объектов, чтобы облегчить поиск и фильтрацию, и мы создали функцию, которая может проверять, является ли данное имя режима охватываемым . Осталось только выполнить фактический анализ, который мы уже упоминали, можно сделать в constructors
наших классов .
class Coordinate {
constructor(x, y) {
this.x = parseInt(x);
this.y = parseInt(y);
}
equals(coordinate) {
return coordinate.x == this.x && coordinate.y == this.y;
}
}
Наш класс Coordinate
, используемый только внутренне другими нашими классами, это красиво и просто. Его конструктор принимает x и ay и разбирает их на целые числа. Я добавил функцию equals
, чтобы мы могли легко сравнить, если два Coordinate
одинаковы.
class Mode {
constructor(arr) {
this.name = arr.pop();
this.coordinates = arr.map(coordinate =>
new Coordinate(coordinate[0], coordinate[1])
);
}
isCoveredBy(modeCoordinates) {
for (const coordinate of this.coordinates) {
if (!!!modeCoordinates.find(c => c.coordinate.equals(coordinate)))
return false;
}
return true;
}
}
Наш конструктор класса Mode
принимает Array
(поскольку coArr
является Array
из Array
с) и вставляет последний член в свое имя , Оставшиеся Array
- это все координаты, поэтому они отображаются в Coordinate
объекты.
class ModeCoordinate {
constructor(input) {
let inputArr = input.replace(/\s/g, "").split(/[^A-Za-z0-9]/);
this.name = inputArr[0];
this.coordinate = new Coordinate(inputArr[1], inputArr[2]);
}
}
Наш класс ModeCoordinate
ожидает строку и использует regex для удаления пробелов (используя заменить ), а затем разбить строку и оставить только буквы c символов. Так, например, "Mode2(1, 2)"
становится ["Mode2", "1", "2"]
. Это позволяет легко сохранить первый элемент в качестве имени и создать Coordinate
из двух последних.
Теперь мы можем собрать все это вместе. Я добавил несколько тестовых данных, чтобы вы могли их запустить:
class Coordinate {
constructor(x, y) {
this.x = parseInt(x);
this.y = parseInt(y);
}
equals(coordinate) {
return coordinate.x == this.x && coordinate.y == this.y;
}
}
class Mode {
constructor(arr) {
this.name = arr.pop();
this.coordinates = arr.map(coordinate =>
new Coordinate(coordinate[0], coordinate[1])
);
}
isCoveredBy(modeCoordinates) {
for (const coordinate of this.coordinates) {
if (!!!modeCoordinates.find(c => c.coordinate.equals(coordinate)))
return false;
}
return true;
}
}
class ModeCoordinate {
constructor(input) {
let inputArr = input.replace(/\s/g, "").split(/[^A-Za-z0-9]/);
this.name = inputArr[0];
this.coordinate = new Coordinate(inputArr[1], inputArr[2]);
}
}
let coArr = [
[[0, 0], [1, 1], [2, 2], "Mode1"],
[[0, 0], [0, 1], [0, 2], "Mode2"],
[[0, 0], [0, 1], [0, 2], "Mode3"],
[[0, 0], [0, 1], [0, 2], "Mode4"],
[[0, 0], [0, 1], [0, 2], "Mode5"],
[[0, 0], [0, 1], [0, 2], "Mode6"]
], strArr = [
"Mode1(0, 0)",
"Mode1(1, 1)",
"Mode1(2, 2)",
"Mode2(0, 0)",
"Mode2(1, 2)",
"Mode2(0, 2)"
];
const modes = coArr.map(x => new Mode(x));
const allModeCoordinates = strArr.map(x => new ModeCoordinate(x));
const isModeCovered = modeName => {
let mode = modes.find(x => x.name == modeName);
let modeCoordinates = allModeCoordinates.filter(x => x.name == modeName);
return mode.isCoveredBy(modeCoordinates);
};
console.log(isModeCovered("Mode1")); // returns true
console.log(isModeCovered("Mode2")); // returns false
Если вы хотите увидеть, покрыты ли все режимы, вы можете запустить функцию, которую мы создали в al oop, для всех режимов в modes
. Очевидно, что здесь нет обработки ошибок - мы действительно ожидаем, что данные будут в формате, который вы показали. Надеемся, что это ответ на ваш вопрос.
Изменить с альтернативным решением, как требуется в комментариях:
class Coordinate {
constructor(x, y) {
this.x = parseInt(x);
this.y = parseInt(y);
}
equals(coordinate) {
return coordinate.x == this.x && coordinate.y == this.y;
}
}
class Mode {
constructor(name, coordinates) {
this.name = name;
this.coordinates = coordinates.map(coordinate =>
new Coordinate(coordinate[0], coordinate[1])
);
}
isCoveredBy(modeCoordinates) {
for (const coordinate of this.coordinates) {
if (!!!modeCoordinates.find(c => c.coordinate.equals(coordinate)))
return false;
}
return true;
}
addCoordinates(coordinates) {
let newCoordinates = coordinates.map(coordinate =>
new Coordinate(coordinate[0], coordinate[1])
);
this.coordinates.concat(newCoordinates);
}
}
class ModeCoordinate {
constructor(input) {
let inputArr = input.replace(/\s/g, "").split(/[^A-Za-z0-9]/);
this.name = inputArr[0];
this.coordinate = new Coordinate(inputArr[1], inputArr[2]);
}
}
let coArr = [
[[0, 0], [1, 1], [2, 2], "Mode1"],
[[0, 0], [2, 2], "Mode3"],
[[0, 0], [0, 1], [0, 2], "Mode2"],
[[1, 1], "Mode3"],
[[0, 0], [0, 1], [0, 2], "Mode4"],
[[0, 0], [0, 1], [0, 2], "Mode5"],
[[0, 0], [0, 1], [0, 2], "Mode6"]
], strArr = [
"Mode1(0, 0)",
"Mode1(1, 1)",
"Mode1(2, 2)",
"Mode2(0, 0)",
"Mode2(1, 2)",
"Mode2(0, 2)",
"Mode3(0, 0)",
"Mode3(1, 1)",
"Mode3(2, 2)"
];
const extractModes = () => {
let modes = [];
for (let item of coArr) {
let name = item.pop();
let mode = modes.find(x => x.name == name);
if (!!mode)
mode.addCoordinates(item);
else
modes.push(new Mode(name, item));
}
return modes;
};
const modes = extractModes();
const allModeCoordinates = strArr.map(x => new ModeCoordinate(x));
const isModeCovered = modeName => {
let mode = modes.find(x => x.name == modeName);
let modeCoordinates = allModeCoordinates.filter(x => x.name == modeName);
return mode.isCoveredBy(modeCoordinates);
};
console.log(isModeCovered("Mode1")); // returns true
console.log(isModeCovered("Mode2")); // returns false
console.log(isModeCovered("Mode3")); // returns true