Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions exercises/practice/linked-list/.meta/example.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ end
function LinkedList:pop()
local v = self._head.v
self._head = self._head.next
if not self._head then
if self._head then
self._head.prev = nil
else
self._tail = nil
end
return v
Expand All @@ -37,6 +39,8 @@ function LinkedList:shift()
self._tail = self._tail.prev
if self._tail then
self._tail.next = nil
else
self._head = nil
end
return v
end
Expand All @@ -52,21 +56,21 @@ function LinkedList:count()
end

function LinkedList:delete(v)
if self._head.v == v then
self:pop()
return
end

local current = self._head
while current do
if current.v == v then
if self._head == current then
self._head = current.next
end
if self._tail == current then
self._tail = current.prev
end
if current.prev then
current.prev.next = current.next
end
if current.next then
current.next.prev = current.prev
end
return
end
current = current.next
end
Expand Down
19 changes: 19 additions & 0 deletions exercises/practice/linked-list/.meta/spec_generator.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
return {
module_name = 'LinkedList',

generate_test = function(case)
local lines = { 'local list = LinkedList()' }

for _, operation in ipairs(case.input.operations) do
if operation.value then
table.insert(lines, ('list:%s(%s)'):format(operation.operation, operation.value))
elseif operation.expected then
table.insert(lines, ('assert.equal(%s, list:%s())'):format(operation.expected, operation.operation))
else
table.insert(lines, ('list:%s()'):format(operation.operation))
end
end

return table.concat(lines, '\n')
end
}
67 changes: 67 additions & 0 deletions exercises/practice/linked-list/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.

[7f7e3987-b954-41b8-8084-99beca08752c]
description = "pop gets element from the list"

[c3f67e5d-cfa2-4c3e-a18f-7ce999c3c885]
description = "push/pop respectively add/remove at the end of the list"

[00ea24ce-4f5c-4432-abb4-cc6e85462657]
description = "shift gets an element from the list"

[37962ee0-3324-4a29-b588-5a4c861e6564]
description = "shift gets first element from the list"

[30a3586b-e9dc-43fb-9a73-2770cec2c718]
description = "unshift adds element at start of the list"

[042f71e4-a8a7-4cf0-8953-7e4f3a21c42d]
description = "pop, push, shift, and unshift can be used in any order"

[88f65c0c-4532-4093-8295-2384fb2f37df]
description = "count an empty list"

[fc055689-5cbe-4cd9-b994-02e2abbb40a5]
description = "count a list with items"

[8272cef5-130d-40ea-b7f6-5ffd0790d650]
description = "count is correct after mutation"

[229b8f7a-bd8a-4798-b64f-0dc0bb356d95]
description = "popping to empty doesn't break the list"

[4e1948b4-514e-424b-a3cf-a1ebbfa2d1ad]
description = "shifting to empty doesn't break the list"

[e8f7c600-d597-4f79-949d-8ad8bae895a6]
description = "deletes the only element"

[fd65e422-51f3-45c0-9fd0-c33da638f89b]
description = "deletes the element with the specified value from the list"

[59db191a-b17f-4ab7-9c5c-60711ec1d013]
description = "deletes the element with the specified value from the list, re-assigns tail"

[58242222-5d39-415b-951d-8128247f8993]
description = "deletes the element with the specified value from the list, re-assigns head"

[ee3729ee-3405-4bd2-9bad-de0d4aa5d647]
description = "deletes the first of two elements"

[47e3b3b4-b82c-4c23-8c1a-ceb9b17cb9fb]
description = "deletes the second of two elements"

[7b420958-f285-4922-b8f9-10d9dcab5179]
description = "delete does not modify the list if the element is not found"

[7e04828f-6082-44e3-a059-201c63252a76]
description = "deletes only the first occurrence"
194 changes: 129 additions & 65 deletions exercises/practice/linked-list/linked-list_spec.lua
Original file line number Diff line number Diff line change
@@ -1,113 +1,177 @@
local LinkedList = require('linked-list')

describe('linked-list', function()
it('should be able to pop pushed elements', function()
it('pop gets element from the list', function()
local list = LinkedList()
list:push(10)
list:push(20)
assert.equal(20, list:pop())
assert.equal(10, list:pop())
list:push(7)
assert.equal(7, list:pop())
end)

it('should be able to shift pushed elements', function()
it('push/pop respectively add/remove at the end of the list', function()
local list = LinkedList()
list:push(10)
list:push(20)
assert.equal(10, list:shift())
assert.equal(20, list:shift())
list:push(11)
list:push(13)
assert.equal(13, list:pop())
assert.equal(11, list:pop())
end)

it('should be able to shift unshifted elements', function()
it('shift gets an element from the list', function()
local list = LinkedList()
list:unshift(10)
list:unshift(20)
assert.equal(20, list:shift())
assert.equal(10, list:shift())
list:push(17)
assert.equal(17, list:shift())
end)

it('should be able to pop unshifted elements', function()
it('shift gets first element from the list', function()
local list = LinkedList()
list:unshift(10)
list:unshift(20)
assert.equal(10, list:pop())
assert.equal(20, list:pop())
list:push(23)
list:push(5)
assert.equal(23, list:shift())
assert.equal(5, list:shift())
end)

it('should be able to count its elements', function()
it('unshift adds element at start of the list', function()
local list = LinkedList()
list:unshift(23)
list:unshift(5)
assert.equal(5, list:shift())
assert.equal(23, list:shift())
end)

it('pop, push, shift, and unshift can be used in any order', function()
local list = LinkedList()
list:push(1)
list:push(2)
assert.equal(2, list:pop())
list:push(3)
assert.equal(1, list:shift())
list:unshift(4)
list:push(5)
assert.equal(4, list:shift())
assert.equal(5, list:pop())
assert.equal(3, list:shift())
end)

it('count an empty list', function()
local list = LinkedList()
assert.equal(0, list:count())
list:push(10)
assert.equal(1, list:count())
list:push(20)
assert.equal(2, list:count())
end)

it('count a list with items', function()
local list = LinkedList()
list:push(37)
list:push(1)
assert.equal(2, list:count())
end)

it('should count correctly after a shift', function()
it('count is correct after mutation', function()
local list = LinkedList()
list:push(10)
list:push(20)
list:push(31)
assert.equal(1, list:count())
list:unshift(43)
assert.equal(2, list:count())
list:shift()
assert.equal(1, list:count())
list:pop()
assert.equal(0, list:count())
end)

it('should count correctly after a pop', function()
it('popping to empty doesn\'t break the list', function()
local list = LinkedList()
list:push(10)
list:push(20)
list:push(41)
list:push(59)
list:pop()
list:pop()
list:push(47)
assert.equal(1, list:count())
assert.equal(47, list:pop())
end)

it('should be able to delete from the beginning of the list', function()
it('shifting to empty doesn\'t break the list', function()
local list = LinkedList()
list:push(10)
list:push(20)
list:push(30)
list:delete(30)
assert.equal(2, list:count())
assert.equal(20, list:pop())
assert.equal(10, list:shift())
list:push(41)
list:push(59)
list:shift()
list:shift()
list:push(47)
assert.equal(1, list:count())
assert.equal(47, list:shift())
end)

it('deletes the only element', function()
local list = LinkedList()
list:push(61)
list:delete(61)
assert.equal(0, list:count())
end)

it('should be able to delete from the middle of the list', function()
it('deletes the element with the specified value from the list', function()
local list = LinkedList()
list:push(10)
list:push(20)
list:push(30)
list:delete(20)
list:push(71)
list:push(83)
list:push(79)
list:delete(83)
assert.equal(2, list:count())
assert.equal(30, list:pop())
assert.equal(10, list:shift())
assert.equal(79, list:pop())
assert.equal(71, list:shift())
end)

it('should be able to delete from the end of the list', function()
it('deletes the element with the specified value from the list, re-assigns tail', function()
local list = LinkedList()
list:push(10)
list:push(20)
list:push(30)
list:delete(10)
list:push(71)
list:push(83)
list:push(79)
list:delete(83)
assert.equal(2, list:count())
assert.equal(30, list:pop())
assert.equal(20, list:shift())
assert.equal(79, list:pop())
assert.equal(71, list:pop())
end)

it('should delete all elements with the matching value', function()
it('deletes the element with the specified value from the list, re-assigns head', function()
local list = LinkedList()
list:push(10)
list:push(20)
list:push(20)
list:push(30)
list:delete(20)
list:push(71)
list:push(83)
list:push(79)
list:delete(83)
assert.equal(2, list:count())
assert.equal(30, list:pop())
assert.equal(10, list:shift())
assert.equal(71, list:shift())
assert.equal(79, list:shift())
end)

it('should be able to delete the only element', function()
it('deletes the first of two elements', function()
local list = LinkedList()
list:push(10)
list:delete(10)
assert.equal(0, list:count())
list:push(97)
list:push(101)
list:delete(97)
assert.equal(1, list:count())
assert.equal(101, list:pop())
end)

it('deletes the second of two elements', function()
local list = LinkedList()
list:push(97)
list:push(101)
list:delete(101)
assert.equal(1, list:count())
assert.equal(97, list:pop())
end)

it('delete does not modify the list if the element is not found', function()
local list = LinkedList()
list:push(89)
list:delete(103)
assert.equal(1, list:count())
end)

it('deletes only the first occurrence', function()
local list = LinkedList()
list:push(73)
list:push(9)
list:push(9)
list:push(107)
list:delete(9)
assert.equal(3, list:count())
assert.equal(107, list:pop())
assert.equal(9, list:pop())
assert.equal(73, list:pop())
end)
end)
Loading