I'm adding objects to a collection inside a for-loop, like this (points is a Point[]):
for (const point of points) {
// do and check some stuff
collection.push(point)
}
I then realized I needed objects to be unique, but since they're of a custom type, I can't use a Set<Point>, which doesn't use the objects' equals function to compare them. My naive approach was checking each of the already assigned objects, which is fine performance-wise since the collection is usually very small:
addPoints: for (const point of points) {
// do and check some stuff
for (const existingPoint of collection) {
if (point.equals(existingPoint)) break addPoints
}
collection.push(point)
}
As you can see, I'm using the break label construct here in order to break out of my outer loop in case I encounter a point I've already added to the collection.
My linter doesn't like this, throwing a "no-labels" violation, whose description states
While convenient in some cases, labels tend to be used only rarely and are frowned upon by some as a remedial form of flow control that is more error prone and harder to understand.
My question is: How can I handle this use case without adding unnecessary complexity?
Things I've considered, but dislike because they add lots of code that feels unnecessarily clunky compared to the label:
- Moving the check into a separate function, which is essentially the inner loop, then call that with a simple
if - breakin my outer loop. - Setting a flag in the inner loop, then checking that in the outer loop in order to
breakout. - Writing a whole wrapper class for my collection that uses
equalsto check for unique members.
CodePudding user response:
How about something like this:
for (const point of points) {
const alreadyExists = collection.some(
(p) => p.x === point.x && p.y === point.y
);
if (!alreadyExists) {
collection.push(point);
}
}
With some function you can write your own comparator and check the object equality with any rule you need
CodePudding user response:
I usually use a Map for things like this, and define the map keys as e.g. strings that make out unique elements:
const map = new Map<string, Point>();
for (const point of points) {
const key = ...
map.set(key, point);
}
const collection = [...map.values()];
This requires that you can build a key from the point attributes that uniquely define a point. You didn't include your Point interface, but if it's a point in space and has x and y properties, you could e.g. do map.set([point.x, point.y].join(';'), point), map.set(JSON.stringify(point), point) or whatever suits your needs.
