@@ -1063,76 +1063,110 @@ JavaScript.
10631063
10641064hint}}
10651065
1066- ### List class
1066+ ### Groups
10671067
1068- {{index "list (exercise)", interface, iterator , "static method ", "List class "}}
1068+ {{index "groups (exercise)", "Set class" , "Group class ", "set (data structure) "}}
10691069
1070- Rewrite the list data structure from the exercises in [ Chapter
1071- ?] ( data#list ) as a ((class)). Give ` List ` objects their old
1072- ` value ` and ` rest ` properties, but also a ` toArray ` method and a
1073- ` length ` getter that returns the length of the list. Make ` fromArray `
1074- a static method on the ` List ` constructor.
1070+ {{id groups}}
10751071
1076- In order for lists to work as a class with methods, we can no longer
1077- represent the empty list as ` null ` , but have to create a special
1078- instance of our class that acts as the empty list placeholder, and
1079- compare with that instance, instead of ` null ` , when checking if we've
1080- reached the end of a list. Store this instance in ` List.empty ` (a
1081- static property).
1072+ The standard JavaScript environment provides another data structure
1073+ called ` Set ` . Like an instance of ` Map ` , a set holds a collection of
1074+ values. Unlike ` Map ` , it does not associate other values with those—it
1075+ just tracks which values are part of the set. A value can only be part
1076+ of a set once—adding it again doesn't have any effect.
1077+
1078+ {{index "add method", "delete method", "has method"}}
1079+
1080+ Write a class called ` Group ` (since ` Set ` is already taken). Like
1081+ ` Set ` , it has ` add ` , ` delete ` , and ` has ` methods. Its constructor
1082+ creates an empty group, ` add ` adds a value to the group (but only if
1083+ it isn't already a member), ` delete ` removes its argument from the
1084+ group (it if was a member), and ` has ` returns a Boolean value
1085+ indicating whether its argument is a member of the group.
1086+
1087+ {{index "=== operator", "indexOf method"}}
1088+
1089+ Use the ` === ` operator, or something equivalent such as ` indexOf ` , to
1090+ determine whether two values are the same.
1091+
1092+ {{index "static method"}}
1093+
1094+ Give the class a static ` from ` method that takes an iteratable object
1095+ as argument and creates a group that contains all the values produced
1096+ by iterating over it.
10821097
10831098{{if interactive
10841099
10851100``` {test: no}
1086- class List {
1101+ class Group {
10871102 // Your code here.
10881103}
10891104
1090- console.log(List.fromArray([10, 20]));
1091- // → {value: 10, rest: {value: 20, rest: null}}
1092- console.log(List.fromArray([10, 20, 30]).toArray());
1093- // → [10, 20, 30]
1094- console.log(new List(2, List.empty).length);
1095- // → 1
1105+ let group = Group.from([10, 20]);
1106+ console.log(group.has(10));
1107+ // → true
1108+ console.log(group.has(30));
1109+ // → false
1110+ group.add(10);
1111+ group.delete(10);
1112+ console.log(group.has(10));
1113+ // → false
10961114```
10971115
10981116if}}
10991117
11001118{{hint
11011119
1102- {{index "list (exercise)"}}
1120+ {{index "groups (exercise)", "Group class", "indexOf method", "includes method"}}
1121+
1122+ The easiest way to do this is to store an ((array)) of group members
1123+ in an instance property. The ` includes ` or ` indexOf ` methods can be
1124+ used to check whether a given value is in the array.
1125+
1126+ {{index "push method"}}
11031127
1104- Your class' constructor should take a value and a rest list as
1105- parameters, and store those in the instance.
1128+ Your class' ((constructor)) can set the member collection to an empty
1129+ array. When ` add ` is called, it must check whether the given value is
1130+ in the array, and add it, for example with ` push ` , otherwise.
11061131
1107- The static ` fromArray ` method can be written inside the class
1108- declaration. The ` empty ` property, because it is not a function, must
1109- be added to the prototype afterwards—but that would have been
1110- necessary anyway, because we couldn't create an instance of ` List `
1111- before we've finished defining the class.
1132+ {{index "filter method"}}
11121133
1113- The value of the empty list object is not important—when using lists
1114- correctly, it should not be read. The ` toArray ` and ` length ` methods
1115- do the right thing automatically, even on this object, if you make the
1116- end conditions of their loops check for ` == List.empty ` .
1134+ Deleting an element from an array, in ` delete ` , is slightly awkward,
1135+ but you can use ` filter ` to create a new array without the value.
1136+ Don't forget to overwrite the property holding the members with the
1137+ newly filtered version of the array.
1138+
1139+ {{index "for/of loop", "iterable interface"}}
1140+
1141+ The ` from ` method can use a ` for ` /` of ` loop to get the values out of
1142+ the iterable object, and call ` add ` to put them into a newly created
1143+ group.
11171144
11181145hint}}
11191146
1120- ### List iteration
1147+ ### Iterable groups
11211148
1122- {{index "list (exercise)", interface, "iterator interface"}}
1149+ {{index "groups (exercise)", interface, "iterator interface", "Group class "}}
11231150
1124- {{id list_iterator }}
1151+ {{id group_iterator }}
11251152
1126- Make the ` List ` class from the previous exercise iterable. Refer back
1153+ Make the ` Group ` class from the previous exercise iterable. Refer back
11271154to the section about the iterator interface earlier in the chapter if
11281155you aren't clear on the exact form of the interface anymore.
11291156
1157+ If you used an array to represent the group's members, don't just
1158+ return the iterator created by calling the ` Symbol.iterator ` method on
1159+ the array. That would work, but defeats the purpose of this exercise.
1160+
1161+ It is okay if your iterator behaves strangely when the group is
1162+ modified during iteration.
1163+
11301164{{if interactive
11311165
11321166``` {test: no}
11331167// Your code here (and the code from the previous exercise)
11341168
1135- for (let value of List.fromArray (["a", "b", "c"])) {
1169+ for (let value of Group.from (["a", "b", "c"])) {
11361170 console.log(value);
11371171}
11381172// → a
@@ -1144,16 +1178,16 @@ if}}
11441178
11451179{{hint
11461180
1147- {{index "list (exercise)"}}
1181+ {{index "groups (exercise)", "Group class", "next method "}}
11481182
1149- It is probably worthwhile to define a new class ` ListIterator ` .
1150- Iterator instances should have a property that tracks the current rest
1151- of the list. If that's the empty list, the ` next ` method can say it is
1152- done. If not, it should return the current element and move the
1153- current rest forward.
1183+ It is probably worthwhile to define a new class ` GroupIterator ` .
1184+ Iterator instances should have a property that tracks the current
1185+ position in the group. Every time ` next ` is called, it checks whether
1186+ it is done, and if not, moves past the current value and returns it.
11541187
1155- The list class itself gets a method named by ` Symbol.iterator ` which,
1156- when called, returns a new instance of the list iterator class.
1188+ The ` Group ` class itself gets a method named by ` Symbol.iterator `
1189+ which, when called, returns a new instance of the iterator class for
1190+ that group.
11571191
11581192hint}}
11591193
0 commit comments