Skip to content

Instantly share code, notes, and snippets.

@jonurry
Created March 15, 2018 11:41
Show Gist options
  • Save jonurry/3445e23c69b70201bf2a313f653bda27 to your computer and use it in GitHub Desktop.
Save jonurry/3445e23c69b70201bf2a313f653bda27 to your computer and use it in GitHub Desktop.
7.3 Persistent Group (Eloquent JavaScript Solutions)
function logSetElements(value1, value2, set) {
console.log('set[' + value1 + '] = ' + value2);
}
class PGroup {
constructor(pg = new Set()) {
this.group = pg;
}
add(item) {
let g = PGroup.from(this.group);
g.group.add(item);
return g;
}
delete(item) {
let g = PGroup.from(this.group);
g.group.delete(item);
return g;
}
has(item) {
return this.group.has(item);
}
static empty() {
return new PGroup();
}
static from(a) {
let g = new PGroup();
for (let item of a) {
g.group.add(item);
}
return g;
}
}
let a = PGroup.empty().add("a");
let ab = a.add("b");
let b = ab.delete("a");
console.log(b.has("b"));
// → true
console.log(a.has("b"));
// → false
console.log(b.has("a"));
// → false
a.group.forEach(logSetElements);
ab.group.forEach(logSetElements);
b.group.forEach(logSetElements);
@jonurry
Copy link
Author

jonurry commented Mar 15, 2018

7.3 Persistent group

Most data structures provided in a standard JavaScript environment aren’t very well suited for persistent use. Arrays have slice and concat methods, which allow us to easily create new arrays without damaging the old one. But Set, for example, has no methods for creating a new set with an item added or removed.

Write a new class PGroup, similar to the Group class from Chapter 6, which stores a set of values. Like Group, it has add, delete, and has methods.

Its add method, however, should return a new PGroup instance with the given member added, and leave the old one unchanged. Similarly, delete creates a new instance without a given member.

The class should work for keys of any type, not just strings. It does not have to be efficient when used with large amounts of keys.

The constructor shouldn’t be part of the class’ interface (though you’ll definitely want to use it internally). Instead, there is an empty instance, PGroup.empty, that can be used as a starting value.

Why do you only need one PGroup.empty value, rather than having a function that creates a new, empty map every time?

@jonurry
Copy link
Author

jonurry commented Mar 15, 2018

Hints

Note: I didn't use the following hints so my solution uses sets instead of arrays.

The most convenient way to represent the set of member values remains is still an array, since those are easy to copy.

When a value is added to the group, you can create a new group with a copy of the original array that has the value added (for example using concat). When a value is deleted, you filter it from the array.

The class’ constructor can take such an array as argument, and store it as the instance’s (only) property. This array is never updated.

To add a property (empty) to a constructor that is not a method, you have to add it to the constructor after the class definition, as a regular property.

You only need one empty instance because all empty groups are the same and instances of the class don’t change. You can create many different groups from that single empty group without affecting it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment