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 - break
in my outer loop. - Setting a flag in the inner loop, then checking that in the outer loop in order to
break
out. - Writing a whole wrapper class for my collection that uses
equals
to 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.