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 Array
s of Mode
s and ModeCoordinate
s 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 Coordinate
s (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 Coordinate
s 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 Array
s) 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