So, I want to start by saying you definitely have lots to learn from right now. It's always a good idea to make some attempts, figure out your approach, and then explain it with any bits of code you can provide, whether it works or not. Your question here isn't the clearest either so I am going to provide my example on how I have interpreted it. I'm also going to explain in a somewhat top-down approach, so this is a bit of a read.
Using the input and description you've given, let's work on a function that takes a mode name and returns true if strArr contains all coordinates that that mode has in coArr. To clarify terms, let's say that if this function returns true we will say that the given mode is covered by strArr. Hopefully you are with me so far.
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);
}
Here we have a function that I've written to do just that. As you can see, I've written this function twice: once using Arrow functions and once using "normal" functions. I am not going to go in-depth about what an Arrow function is in Javascript and you will see the rest of this example using them. If you need to familiarize yourself with them now is a great time to do so, but you might also be able to understand them just from comparing the two functions above. Anyway, let's move on and look at what this function is actually is doing.
let mode = coArr.find(x => x.name == modeName);
Here we're using the find function to find the first item in coArr that has a name equal to the given mode name. As you can see in the link, find searches each item of the Array it is performed on and returns the first item that makes the given callback return true. The callback we have given it will not work. That is because it is assuming each item of coArr is an object that has a name. The next line, where we are filtering strArr, will also not work for a similar reason.
Why did I do this?
I did this because the data, in the form that it has been given is - to be blunt - a headache. You can absolutely solve this problem without modifying the data but there are many reasons why I prefer to that I will explain later. So, we are going to assume that we have taken the data given and parsed it into more usable forms:
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);
};
Alright, here is some slightly modified code. We see that it is mapping coArr to a new Array of an object called Mode and mapping strArr to a new Array of an object called ModeCoordinate. We can worry about how the constructor for those objects are handling that later, but for clarity's sake here is a brief idea of what those objects look like (in pseudo-JS, this won't compile):
class Coordinate {
int x,
int y
}
class Mode {
string name,
Coordinate[] coordinates // an Array of Coordinates
}
class ModeCoordinate {
string name,
Coordinate coordinate
}
If our data is in Arrays of Modes and ModeCoordinates we can easily search by their name and find their associating Coordinate(s). Once we can easily do that most of the work is done for us and we just have to determine the details of the logic behind the last line of the function:
return mode.isCoveredBy(modeCoordinates);
Let's add that function, isCoveredBy to the Mode class:
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;
}
}
It's a short method, but let's quickly go through it. We use a for of to loop through every Coordinate in the Mode's coordinates. Then, we use an if to test if we can find that Coordinate in the Array of given Coordinates (which, if you rememeber, are taken from strArr who have the same mode name as the Mode we are in). If we can't find one we immediately return false because is order for the mode to be "covered" we stated that every single coordinate needs to also exist in strArr. If it hasn't returned false at any point, we return true at the end of the loop because that means they were all found.
There's a chance that this line, the if condition, may be confusing:
!!!modeCoordinates.find(c => c.coordinate.equals(coordinate))
We can briefly break that down. modeCoordinates.find(c => c.coordinate.equals(coordinate)) is taking modeCoordinates which, if you recall, is a ModeCoordinate Array that we have mapped all our strArr items into and filtered it by the mode name of the Mode we are in, and trying to find one that has a Coordinate equal to the coordinate of our current loop iteration. It returns back the item, if found, or falsy if not found. The !!! in front of it is a combination of a regular !, or not, operator and a !! operator, which forces the returned value into a boolean.
Alright, so now we know we have to parse the given data into our nicer object types to make our find and filters easy breezy and we've created the function that can test to see if a given mode name is covered. All that is left is to do the actual parsing, which we already mentioned can be done in the constructors of our classes.
class Coordinate {
constructor(x, y) {
this.x = parseInt(x);
this.y = parseInt(y);
}
equals(coordinate) {
return coordinate.x == this.x && coordinate.y == this.y;
}
}
Our Coordinate class, used only internally by our other classes, is nice and simple. Its constructor accepts an x and a y and parses them into integers. I added an equals function so that we can easily compare if two Coordinates are the same.
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;
}
}
Our Mode class's contructor takes an Array (since coArr is an Array of Arrays) and pops the last member into its name. The remaining Array is all coordinates so they are mapped into Coordinate objects.
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]);
}
}
Our ModeCoordinate class expects a string and uses regex to remove whitespace (using replace) and then split the string and leave only alphanumeric characters. So for example, "Mode2(1, 2)" becomes ["Mode2", "1", "2"]. This names it easy to store the first item as the name and create a Coordinate from the last two.
Now we can put it all together. I've added some test data so you can run it:
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
If you want to see if all modes are "covered" you can run the function we created in a loop over all modes in modes. Obviously there isn't any error handling here - we're really expecting the data to be in the format you've shown. Hopefully this answers your question.
Edit with alternative solution as requested in comments:
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