| 4 | 4 | // |
| 5 | 5 | |
| 6 | 6 | export class List { |
| 7 | constructor() { | |
| 8 | throw new Error('Remove this line and implement the function'); | |
| 7 | constructor(values = []) { | |
| 8 | this.values = values; | |
| 9 | 9 | } |
| 10 | 10 | |
| 11 | 11 | /** |
| 13 | 13 | * @return {List} |
| 14 | 14 | */ |
| 15 | 15 | append(other) { |
| 16 | throw new Error('Remove this line and implement the function'); | |
| 16 | // Edge Case: Appending an empty list should return the original list | |
| 17 | if (other.length() === 0) { | |
| 18 | return new List(this.values); | |
| 19 | } | |
| 20 | ||
| 21 | // Edge Case: Appending to an empty list should return the other list | |
| 22 | if (this.length() === 0) { | |
| 23 | return new List(other.values); | |
| 24 | } | |
| 25 | ||
| 26 | return new List([...this.values, ...other.values]); | |
| 17 | 27 | } |
| 18 | 28 | |
| 19 | 29 | /** |
| 21 | 31 | * @return {List} |
| 22 | 32 | */ |
| 23 | 33 | concat(others) { |
| 24 | throw new Error('Remove this line and implement the function'); | |
| 34 | // Edge Case: Concatenating with an empty list should return the original list | |
| 35 | if (others.length() === 0) { | |
| 36 | return new List(this.values); | |
| 37 | } | |
| 38 | ||
| 39 | let result = [...this.values]; | |
| 40 | ||
| 41 | // Edge Case: Handling nested lists in concat | |
| 42 | for (let i = 0; i < others.length(); i++) { | |
| 43 | const item = others.values[i]; | |
| 44 | if (item instanceof List) { | |
| 45 | result = [...result, ...item.values]; | |
| 46 | } else { | |
| 47 | result.push(item); | |
| 48 | } | |
| 49 | } | |
| 50 | ||
| 51 | return new List(result); | |
| 25 | 52 | } |
| 26 | 53 | |
| 27 | 54 | /** |
| 29 | 56 | * @return {List} |
| 30 | 57 | */ |
| 31 | 58 | filter(predicate) { |
| 32 | throw new Error('Remove this line and implement the function'); | |
| 59 | // Edge Case: Filtering an empty list should return an empty list | |
| 60 | if (this.length() === 0) { | |
| 61 | return new List([]); | |
| 62 | } | |
| 63 | ||
| 64 | const result = []; | |
| 65 | for (let i = 0; i < this.values.length; i++) { | |
| 66 | if (predicate(this.values[i])) { | |
| 67 | result.push(this.values[i]); | |
| 68 | } | |
| 69 | } | |
| 70 | ||
| 71 | return new List(result); | |
| 33 | 72 | } |
| 34 | 73 | |
| 35 | 74 | /** |
| 37 | 76 | * @return {List} |
| 38 | 77 | */ |
| 39 | 78 | map(expression) { |
| 40 | throw new Error('Remove this line and implement the function'); | |
| 79 | // Edge Case: Mapping over an empty list should return an empty list | |
| 80 | if (this.length() === 0) { | |
| 81 | return new List([]); | |
| 82 | } | |
| 83 | ||
| 84 | const result = []; | |
| 85 | for (let i = 0; i < this.values.length; i++) { | |
| 86 | result.push(expression(this.values[i])); | |
| 87 | } | |
| 88 | ||
| 89 | return new List(result); | |
| 41 | 90 | } |
| 42 | 91 | |
| 43 | 92 | /** |
| 44 | 93 | * @return {number} |
| 45 | 94 | */ |
| 46 | 95 | length() { |
| 47 | throw new Error('Remove this line and implement the function'); | |
| 96 | // Edge Case: Length of an empty list should be 0 | |
| 97 | let count = 0; | |
| 98 | for (let i = 0; i < this.values.length; i++) { | |
| 99 | count++; | |
| 100 | } | |
| 101 | return count; | |
| 48 | 102 | } |
| 49 | 103 | |
| 50 | 104 | /** |
| 53 | 107 | * @return {any} |
| 54 | 108 | */ |
| 55 | 109 | foldl(callback, initial) { |
| 56 | throw new Error('Remove this line and implement the function'); | |
| 110 | // Edge Case: Folding an empty list should return the initial value | |
| 111 | if (this.length() === 0) { | |
| 112 | return initial; | |
| 113 | } | |
| 114 | ||
| 115 | let accumulator = initial; | |
| 116 | for (let i = 0; i < this.values.length; i++) { | |
| 117 | accumulator = callback(accumulator, this.values[i]); | |
| 118 | } | |
| 119 | ||
| 120 | return accumulator; | |
| 57 | 121 | } |
| 58 | 122 | |
| 59 | 123 | /** |
| 62 | 126 | * @return {any} |
| 63 | 127 | */ |
| 64 | 128 | foldr(callback, initial) { |
| 65 | throw new Error('Remove this line and implement the function'); | |
| 129 | // Edge Case: Folding an empty list should return the initial value | |
| 130 | if (this.length() === 0) { | |
| 131 | return initial; | |
| 132 | } | |
| 133 | ||
| 134 | let accumulator = initial; | |
| 135 | for (let i = this.values.length - 1; i >= 0; i--) { | |
| 136 | accumulator = callback(accumulator, this.values[i]); | |
| 137 | } | |
| 138 | ||
| 139 | return accumulator; | |
| 66 | 140 | } |
| 67 | 141 | |
| 68 | 142 | /** |
| 69 | 143 | * @return {List} |
| 70 | 144 | */ |
| 71 | 145 | reverse() { |
| 72 | throw new Error('Remove this line and implement the function'); | |
| 146 | // Edge Case: Reversing an empty list should return an empty list | |
| 147 | if (this.length() === 0) { | |
| 148 | return new List([]); | |
| 149 | } | |
| 150 | ||
| 151 | const result = []; | |
| 152 | for (let i = this.values.length - 1; i >= 0; i--) { | |
| 153 | result.push(this.values[i]); | |
| 154 | } | |
| 155 | ||
| 156 | return new List(result); | |
| 73 | 157 | } |
| 74 | 158 | } |
| 159 | ||
| 160 | // Handled Edge Cases: Appending an empty list, appending to an empty list, concatenating with an empty list, handling nested lists in concat, filtering an empty list, mapping over an empty list, length of an empty list, folding an empty list, reversing an empty list |