Skip to content

Commit c9e1ddb

Browse files
committed
changing linked list types module to functional programming
1 parent 39ed6e0 commit c9e1ddb

File tree

11 files changed

+273
-542
lines changed

11 files changed

+273
-542
lines changed
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
(function (exports) {
2-
const {linked} = require('./linked.proto.module')
3-
4-
Object.assign(exports, {linked})
2+
const linked = require('./linked')
3+
Object.assign(exports, linked)
54
}((typeof module.exports !== 'undefined') ? module.exports : window))
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
(function (exports) {
2+
// helper functions
3+
const compose = (...fns) => data => fns.reduce((v, f) => f(v), data)
4+
5+
// makes Concatenative Inheritance
6+
const inherit = (...protos) => Object.assign({}, ...protos)
7+
8+
/**
9+
base prototype for all linked list types
10+
11+
all functions are pure functions, since they don't realy on external state
12+
and produces no side effects, since they are not mutating external objects
13+
**/
14+
const base = {
15+
node (data, ...rest) {
16+
const prev = (rest[0] === 'double') ? {prev: null} : {}
17+
return Object.assign({}, {data, next: null}, prev)
18+
},
19+
setHead (options) {
20+
let {head, data} = options
21+
Object.assign(options, {head: data})
22+
return options
23+
},
24+
setCurrent (options) {
25+
let {current, data} = options
26+
Object.assign(options, {current: data})
27+
return options
28+
},
29+
setLength (options) {
30+
let {length, data} = options
31+
length += ((data) ? 1 : -1)
32+
Object.assign(options, {length})
33+
return options
34+
},
35+
setNext (options) {
36+
let {data} = options
37+
Object.assign(options.current, {next: data})
38+
return options
39+
},
40+
findPrev (options) {
41+
let {head, data} = options
42+
let c = head
43+
while (!(c.next === null)) {
44+
if (c.next.data === data) {
45+
return c
46+
} else {
47+
c = c.next
48+
}
49+
}
50+
return false
51+
}
52+
}
53+
54+
// single-linked list prototype
55+
const single = {
56+
getState () {
57+
return this
58+
},
59+
setState (options) {
60+
Object.assign(this, options)
61+
},
62+
add (data) {
63+
// retrieves the variables and concatenate the new node to be added
64+
const options = Object.assign(this.getState(), {data: this.node(data)})
65+
const fns = (!this.head && !this.current) ? [this.setHead] : [this.setNext]
66+
// and through function composition, adds an element to the list
67+
// and the result object it's going to be re assign it to the current state
68+
compose(...fns, this.setCurrent, this.setLength, this.setState)(options)
69+
},
70+
remove (data) {
71+
// retrieves variables
72+
const options = Object.assign(this.getState(), {data})
73+
// look if there's a previous link
74+
const prev = this.findPrev(options)
75+
let values, fns
76+
if (prev && !(prev.next === null)) {
77+
// updates the corresponding values to remove the requested object
78+
values = {current: prev, data: prev.next.next}
79+
// functions need to compose to remove the object requested
80+
fns = [this.setNext, this.setState]
81+
} else {
82+
values = {data: options.head.next}
83+
fns = [this.setHead, this.setState]
84+
}
85+
compose(...fns)(Object.assign(options, values)) // removes the object
86+
this.setLength(Object.assign(options, {data: false})) // decreases the length
87+
},
88+
reverse() {
89+
let prev = null
90+
let node = this.head
91+
92+
while (node) {
93+
let save = node.next
94+
node.next = prev
95+
prev = node
96+
node = save
97+
}
98+
Object.assign(this.getState(), {head: prev})
99+
},
100+
display () {
101+
let c = this.head
102+
let show = ''
103+
while (!(c === null)) {
104+
show += `${c.data} ${(c.next !== null) ? ' -> ' : ''}`
105+
c = c.next
106+
}
107+
return show
108+
},
109+
contains (data) {
110+
let c = this.head
111+
while (!(c === null)) {
112+
if (c.data === data) {
113+
return true
114+
}
115+
c = c.next
116+
}
117+
return false
118+
}, // the next functions returns a copy of the object requested
119+
getCurrent() {
120+
return Object.assign({}, this.current)
121+
},
122+
getList() {
123+
return Object.assign({}, this.head)
124+
},
125+
size() {
126+
return this.length
127+
}
128+
}
129+
130+
// double-linked list prototype
131+
const double = {
132+
add (data) {
133+
const options = Object.assign(this.getState(), {data: this.node(data, 'double')})
134+
const fns = (!this.head && !this.current) ? [this.setHead] : [this.setNext, this.setPrev]
135+
compose(...fns, this.setCurrent, this.setLength, this.setState)(options)
136+
},
137+
remove (data) {
138+
const options = Object.assign(this.getState(), {data})
139+
let prev = this.findPrev(options)
140+
let values, fns
141+
if (prev && !(prev.next === null)) {
142+
values = {current: prev, data: prev.next.next}
143+
fns = [this.setPrev, this.setNext, this.setState]
144+
} else {
145+
values = {
146+
data: {
147+
data: options.head.next.data,
148+
next: options.head.next.next,
149+
prev: null
150+
}
151+
}
152+
fns = [this.setHead, this.setState]
153+
}
154+
compose(...fns)(Object.assign(options, values))
155+
this.setLength(Object.assign(options, {data: false}))
156+
}
157+
}
158+
159+
// circular-linked list prototype
160+
const circular = {
161+
display () {
162+
let c = this.head
163+
let show = `${c.data} ${(c.next !== this.head) ? ' -> ' : ''}`
164+
while (!(c.next === this.head)) {
165+
show += `${c.next.data} ${(c.next !== this.head) ? ' -> ' : ''}`
166+
c = c.next
167+
}
168+
return show
169+
},
170+
contains(data) {
171+
let c = this.head
172+
while (!(c.next === this.head)) {
173+
if (c.data === data) {
174+
return true
175+
}
176+
c = c.next
177+
}
178+
return false
179+
}
180+
}
181+
182+
const singleLL = () => {
183+
const variables = { head: null, current: null, length: 0 }
184+
const proto = inherit(base, single)
185+
return Object.assign(Object.create(proto), variables)
186+
}
187+
188+
const doubleLL = () => {
189+
// fn to set the prev link object in the double-linked list
190+
const setPrev = (options) => {
191+
let {current, data} = options
192+
if (data !== null) {
193+
Object.assign(options.data, {prev: current})
194+
}
195+
return options
196+
}
197+
198+
const variables = { head: null, current: null, length: 0 }
199+
// first is updated the base prototype
200+
const b = Object.assign(base, {setPrev})
201+
/*
202+
then we make an Concatenative Inheritance
203+
with the base prototype that give us the basic operations,
204+
with the single prototype that gives the linked lists interface
205+
and finally set the double prototype that overrides the needed methods
206+
*/
207+
const proto = inherit(b, single, double)
208+
/*
209+
and finally return the created prototype with its variables
210+
creating the variables in each type of linked list
211+
avoids the shared state on the prototype
212+
*/
213+
return Object.assign(Object.create(proto), variables)
214+
}
215+
216+
const circularLL = () => {
217+
const setHead = (options) => {
218+
let {data} = options
219+
Object.assign(options, {head: data})
220+
Object.assign(options.head, {next: options.head})
221+
return options
222+
}
223+
const setNext = (options) => {
224+
let {data} = options
225+
let next
226+
if(data.next === null) {
227+
Object.assign(data, {next: options.head})
228+
}
229+
Object.assign(options.current, {next: data})
230+
return options
231+
}
232+
const setPrev = (options) => {
233+
let {data} = options
234+
let next
235+
if(data === null) {
236+
Object.assign(data, {data: options.head})
237+
} else {
238+
Object.assign(data, {prev: options.current})
239+
}
240+
return options
241+
}
242+
243+
const variables = {head: null, current: null, length: 0}
244+
const b = Object.assign(base, {setHead, setNext, setPrev})
245+
const proto = inherit(b, single, double, circular)
246+
247+
return Object.assign(Object.create(proto), variables)
248+
}
249+
250+
Object.assign(exports, {singleLL, doubleLL, circularLL})
251+
252+
}((typeof module.exports !== undefined) ? module.exports : window))

0 commit comments

Comments
 (0)