所以,我想首先说你现在肯定有很多东西要学习。做一些尝试,找出你的方法,然后用你能提供的任何代码解释它,不管它是否有效,这总是一个好主意。你在这里的问题也不是最清楚的,所以我将提供我如何解释它的例子。我还将以某种top-down 的方式进行解释,因此需要阅读一下。
使用您提供的输入和描述,让我们处理一个函数,该函数采用模式名称,如果strArr 包含该模式在coArr 中的所有坐标,则返回true。为了澄清术语,假设如果此函数返回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);
}
这里我们有一个我写的函数来做这件事。如您所见,我已经编写了两次此函数:一次使用Arrow functions,一次使用“普通”函数。我不会深入讨论 Javascript 中的箭头函数是什么,您将看到本示例的其余部分使用它们。如果您现在需要熟悉它们是一个很好的时机,但是您也可以通过比较上面的两个函数来理解它们。不管怎样,让我们继续看看这个函数到底在做什么。
let mode = coArr.find(x => x.name == modeName);
这里我们使用find 函数来查找coArr 中名称与给定模式名称相同的第一项。正如您在链接中看到的,find 搜索执行它的Array 的每个项目,并返回使给定回调返回 true 的第一个项目。我们给它的回调将不起作用。这是因为它假设coArr 的每个项目都是一个具有name 的对象。下一行,我们所在的 filtering 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);
};
好的,这里有一些稍微修改过的代码。我们看到它是 mapping 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
}
如果我们的数据在Modes 和ModeCoordinates 中的Arrays 中,我们可以轻松地按它们的名称搜索并找到它们的关联坐标。一旦我们可以轻松地做到这一点,大部分工作就为我们完成了,我们只需要确定函数最后一行背后的逻辑细节:
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;
}
}
这是一个简短的方法,但让我们快速完成它。我们使用for of 循环遍历Mode 的coordinates 中的每个Coordinate。然后,我们使用if 来测试我们是否可以在给定的Coordinates 的Array 中找到Coordinate(如果你还记得的话,它取自strArr,其模式名称与Mode 我们在)。如果找不到,我们会立即返回false,因为要“覆盖”模式,我们声明每个坐标 也需要存在于strArr 中。如果它在任何时候都没有返回false,我们在循环结束时返回true,因为这意味着它们都被找到了。
if 条件这一行可能会令人困惑:
!!!modeCoordinates.find(c => c.coordinate.equals(coordinate))
我们可以简单地分解一下。 modeCoordinates.find(c => c.coordinate.equals(coordinate)) 采用 modeCoordinates,如果你还记得,它是一个 ModeCoordinate Array,我们已将所有 strArr 项目映射到并通过我们所在的 Mode 的模式名称对其进行过滤,并且试图找到一个Coordinate 等于我们当前循环迭代的坐标的。如果找到,则返回该项目,如果未找到,则返回错误。前面的!!! 是常规!(或非)运算符和!! 运算符的组合,它将返回值强制为布尔值。
好的,所以现在我们知道我们必须将给定的数据解析为更好的对象类型,以使我们的查找和过滤变得轻松,我们已经创建了可以测试给定模式名称是否为 的函数覆盖。剩下的就是进行实际的解析,我们已经提到可以在我们的classes 的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 和一个 y 并将它们解析为整数。我添加了一个equals 函数,以便我们可以轻松比较两个Coordinates 是否相同。
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 是Arrays 的Array)和pops 名称的最后一个成员。剩余的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 删除空格(使用replace)然后split 字符串并只留下字母数字字符。例如,"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
如果您想查看 所有 模式是否被“覆盖”,您可以在 modes 中的所有模式上循环运行我们创建的函数。显然这里没有任何错误处理 - 我们真的希望数据采用您显示的格式。希望这能回答您的问题。
使用 cmets 中要求的替代解决方案进行编辑:
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