Skip to content

Commit

Permalink
Update Swift tools version to 6.0 and enhance list operations functio…
Browse files Browse the repository at this point in the history
…nality
  • Loading branch information
meatball133 committed Dec 22, 2024
1 parent 30f8e4c commit 4b4f469
Show file tree
Hide file tree
Showing 10 changed files with 500 additions and 137 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Node<T> {
class Node<T : Equatable > : Equatable {
var value: T?
var next: Node?
var prev: Node?
Expand All @@ -10,9 +10,12 @@ class Node<T> {
self.value = value
}

static func == (lhs: Node<T>, rhs: Node<T>) -> Bool {
return lhs.value == rhs.value
}
}

class Deque<T> {
class Deque<T : Equatable > {
var count: Int = 0
var head: Node<T>
var tail: Node<T>
Expand All @@ -27,6 +30,27 @@ class Deque<T> {
return self.count == 0
}

func delete(_ value: T) {
var current: Node<T>? = self.head
while current != nil {
if current?.value == value {
if current == self.head {
self.head = self.head.next ?? Node<T>()
self.head.prev = nil
} else if current == self.tail {
self.tail = self.tail.prev ?? Node<T>()
self.tail.next = nil
} else {
current?.prev?.next = current?.next
current?.next?.prev = current?.prev
}
self.count -= 1
break
}
current = current?.next
}
}

func push(_ value: T) {
let node = Node<T>(value: value)
if self.isEmpty() {
Expand Down
27 changes: 27 additions & 0 deletions exercises/practice/linked-list/.meta/template.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Testing
import Foundation
@testable import {{exercise|camelCase}}

let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false

@Suite struct {{exercise|camelCase}}Tests {
{% for case in cases %}
{% if forloop.first -%}
@Test("{{case.description}}")
{% else -%}
@Test("{{case.description}}", .enabled(if: RUNALL))
{% endif -%}
func test{{case.description |camelCase }}() {
let deque = Deque<Int>()
{%- for operation in case.input.operations -%}
{%- if operation.operation == "count" -%}
#expect(deque.{{operation.operation}} == {{operation.expected}})
{%- elif operation.expected -%}
#expect(deque.{{operation.operation}}() == {{operation.expected}})
{%- else -%}
deque.{{operation.operation}}({{operation.value}})
{%- endif -%}
{%- endfor -%}
}
{% endfor -%}
}
2 changes: 1 addition & 1 deletion exercises/practice/linked-list/Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.3
// swift-tools-version:6.0

import PackageDescription

Expand Down
Original file line number Diff line number Diff line change
@@ -1,51 +1,206 @@
import XCTest
import Foundation
import Testing

@testable import LinkedList

class LinkedListTests: XCTestCase {

func testPushPop() {
let deque = Deque<Int>()
deque.push(10)
deque.push(20)
XCTAssertEqual(20, deque.pop() ?? 0 )
XCTAssertEqual(10, deque.pop() ?? 0 )
}

func testPushShift() {
let deque = Deque<Int>()
deque.push(10)
deque.push(20)
XCTAssertEqual(10, deque.shift() ?? 0 )
XCTAssertEqual(20, deque.shift() ?? 0 )
}

func testUnshiftShift() {
let deque = Deque<Int>()
deque.unshift(10)
deque.unshift(20)
XCTAssertEqual(20, deque.shift() ?? 0 )
XCTAssertEqual(10, deque.shift() ?? 0 )
}

func testUnshiftPop() {
let deque = Deque<Int>()
deque.unshift(10)
deque.unshift(20)
XCTAssertEqual(10, deque.pop() ?? 0 )
XCTAssertEqual(20, deque.pop() ?? 0 )
}

func testExampleMethodLength() {
let deque = Deque<Int>()
deque.push(10)
deque.push(20)
XCTAssertEqual(20, deque.pop() ?? 0 )
deque.push(30)
XCTAssertEqual(10, deque.shift() ?? 0 )
deque.unshift(40)
deque.push(50)
XCTAssertEqual(40, deque.shift() ?? 0 )
XCTAssertEqual(50, deque.pop() ?? 0 )
XCTAssertEqual(30, deque.shift() ?? 0 )
}
let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false

@Suite struct LinkedListTests {

@Test("pop gets element from the list")
func testPopGetsElementFromTheList() {
let deque = Deque<Int>()
deque.push(7)
#expect(deque.pop() == 7)
}

@Test("push/pop respectively add/remove at the end of the list", .enabled(if: RUNALL))
func testPushpopRespectivelyAddremoveAtTheEndOfTheList() {
let deque = Deque<Int>()
deque.push(11)
deque.push(13)
#expect(deque.pop() == 13)
#expect(deque.pop() == 11)
}

@Test("shift gets an element from the list", .enabled(if: RUNALL))
func testShiftGetsAnElementFromTheList() {
let deque = Deque<Int>()
deque.push(17)
#expect(deque.shift() == 17)
}

@Test("shift gets first element from the list", .enabled(if: RUNALL))
func testShiftGetsFirstElementFromTheList() {
let deque = Deque<Int>()
deque.push(23)
deque.push(5)
#expect(deque.shift() == 23)
#expect(deque.shift() == 5)
}

@Test("unshift adds element at start of the list", .enabled(if: RUNALL))
func testUnshiftAddsElementAtStartOfTheList() {
let deque = Deque<Int>()
deque.unshift(23)
deque.unshift(5)
#expect(deque.shift() == 5)
#expect(deque.shift() == 23)
}

@Test("pop, push, shift, and unshift can be used in any order", .enabled(if: RUNALL))
func testPopPushShiftAndUnshiftCanBeUsedInAnyOrder() {
let deque = Deque<Int>()
deque.push(1)
deque.push(2)
#expect(deque.pop() == 2)
deque.push(3)
#expect(deque.shift() == 1)
deque.unshift(4)
deque.push(5)
#expect(deque.shift() == 4)
#expect(deque.pop() == 5)
#expect(deque.shift() == 3)
}

@Test("count an empty list", .enabled(if: RUNALL))
func testCountAnEmptyList() {
let deque = Deque<Int>()
#expect(deque.count == 0)
}

@Test("count a list with items", .enabled(if: RUNALL))
func testCountAListWithItems() {
let deque = Deque<Int>()
deque.push(37)
deque.push(1)
#expect(deque.count == 2)
}

@Test("count is correct after mutation", .enabled(if: RUNALL))
func testCountIsCorrectAfterMutation() {
let deque = Deque<Int>()
deque.push(31)
#expect(deque.count == 1)
deque.unshift(43)
#expect(deque.count == 2)
deque.shift()
#expect(deque.count == 1)
deque.pop()
#expect(deque.count == 0)
}

@Test("popping to empty doesn't break the list", .enabled(if: RUNALL))
func testPoppingToEmptyDoesntBreakTheList() {
let deque = Deque<Int>()
deque.push(41)
deque.push(59)
deque.pop()
deque.pop()
deque.push(47)
#expect(deque.count == 1)
#expect(deque.pop() == 47)
}

@Test("shifting to empty doesn't break the list", .enabled(if: RUNALL))
func testShiftingToEmptyDoesntBreakTheList() {
let deque = Deque<Int>()
deque.push(41)
deque.push(59)
deque.shift()
deque.shift()
deque.push(47)
#expect(deque.count == 1)
#expect(deque.shift() == 47)
}

@Test("deletes the only element", .enabled(if: RUNALL))
func testDeletesTheOnlyElement() {
let deque = Deque<Int>()
deque.push(61)
deque.delete(61)
#expect(deque.count == 0)
}

@Test("deletes the element with the specified value from the list", .enabled(if: RUNALL))
func testDeletesTheElementWithTheSpecifiedValueFromTheList() {
let deque = Deque<Int>()
deque.push(71)
deque.push(83)
deque.push(79)
deque.delete(83)
#expect(deque.count == 2)
#expect(deque.pop() == 79)
#expect(deque.shift() == 71)
}

@Test(
"deletes the element with the specified value from the list, re-assigns tail",
.enabled(if: RUNALL))
func testDeletesTheElementWithTheSpecifiedValueFromTheListReAssignsTail() {
let deque = Deque<Int>()
deque.push(71)
deque.push(83)
deque.push(79)
deque.delete(83)
#expect(deque.count == 2)
#expect(deque.pop() == 79)
#expect(deque.pop() == 71)
}

@Test(
"deletes the element with the specified value from the list, re-assigns head",
.enabled(if: RUNALL))
func testDeletesTheElementWithTheSpecifiedValueFromTheListReAssignsHead() {
let deque = Deque<Int>()
deque.push(71)
deque.push(83)
deque.push(79)
deque.delete(83)
#expect(deque.count == 2)
#expect(deque.shift() == 71)
#expect(deque.shift() == 79)
}

@Test("deletes the first of two elements", .enabled(if: RUNALL))
func testDeletesTheFirstOfTwoElements() {
let deque = Deque<Int>()
deque.push(97)
deque.push(101)
deque.delete(97)
#expect(deque.count == 1)
#expect(deque.pop() == 101)
}

@Test("deletes the second of two elements", .enabled(if: RUNALL))
func testDeletesTheSecondOfTwoElements() {
let deque = Deque<Int>()
deque.push(97)
deque.push(101)
deque.delete(101)
#expect(deque.count == 1)
#expect(deque.pop() == 97)
}

@Test("delete does not modify the list if the element is not found", .enabled(if: RUNALL))
func testDeleteDoesNotModifyTheListIfTheElementIsNotFound() {
let deque = Deque<Int>()
deque.push(89)
deque.delete(103)
#expect(deque.count == 1)
}

@Test("deletes only the first occurrence", .enabled(if: RUNALL))
func testDeletesOnlyTheFirstOccurrence() {
let deque = Deque<Int>()
deque.push(73)
deque.push(9)
deque.push(9)
deque.push(107)
deque.delete(9)
#expect(deque.count == 3)
#expect(deque.pop() == 107)
#expect(deque.pop() == 9)
#expect(deque.pop() == 73)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ struct ListOps {
return result
}

static func concat<T: Equatable>(_ arrays: [T]...) -> [T] {
static func concat<T: Equatable>(_ arrays: [[T]]) -> [T] {
var result = [T]()

for array in arrays {
result = append(result, array)
for value in array {
result.append(value)
}
}

return result
Expand Down Expand Up @@ -54,7 +56,7 @@ struct ListOps {
if length(array) == 0 {
return accumulated
} else {
return foldLeft(Array(array.dropFirst()), accumulated: combine(accumulated, array[0]), combine: combine)
return foldLeft(Array(array.dropFirst()), accumulated: combine(array[0], accumulated), combine: combine)
}
}

Expand Down
Loading

0 comments on commit 4b4f469

Please sign in to comment.