I have been using the Chatto framework for working in a chat application. Everything works fine. Now I want to delete a chat message from DataSource which is SlidingDataSource class. The indexing of the array is being handled with some properties like windowOffset itemsOffset windowCount along with the array's count. If anyone has used delete operation in Chatto, Please explain the properties or provide a simple function to delete will be helpful.
Thank you. I am attaching the data source code here..
import Foundation
import Chatto
public enum InsertPosition {
case top
case bottom
}
public class SlidingDataSource<Element> {
private var pageSize: Int
private var windowOffset: Int
private var windowCount: Int
private var itemGenerator: (() -> Element)?
private var items = [Element]()
private var itemsOffset: Int
public var itemsInWindow: [Element] {
let offset = self.windowOffset - self.itemsOffset
return Array(items[offset..<offset+self.windowCount])
}
public init(count: Int, pageSize: Int, itemGenerator: (() -> Element)?) {
self.windowOffset = count
self.itemsOffset = count
self.windowCount = 0
self.pageSize = pageSize
self.itemGenerator = itemGenerator
self.generateItems(min(pageSize, count), position: .top)
}
public convenience init(items: [Element], pageSize: Int) {
var iterator = items.makeIterator()
self.init(count: items.count, pageSize: pageSize) { iterator.next()! }
}
private func generateItems(_ count: Int, position: InsertPosition) {
// swiftlint:disable:next empty_count
guard count > 0 else { return }
guard let itemGenerator = self.itemGenerator else {
fatalError("Can't create messages without a generator")
}
for _ in 0..<count {
self.insertItem(itemGenerator(), position: .top)
}
}
public func insertItem(_ item: Element, position: InsertPosition) {
if position == .top {
self.items.insert(item, at: 0)
let shouldExpandWindow = self.itemsOffset == self.windowOffset
self.itemsOffset -= 1
if shouldExpandWindow {
self.windowOffset -= 1
self.windowCount += 1
}
} else {
let shouldExpandWindow = self.itemsOffset + self.items.count == self.windowOffset + self.windowCount
if shouldExpandWindow {
self.windowCount += 1
}
self.items.append(item)
}
}
public func hasPrevious() -> Bool {
return self.windowOffset > 0
}
public func hasMore() -> Bool {
return self.windowOffset + self.windowCount < self.itemsOffset + self.items.count
}
public func loadPrevious() {
let previousWindowOffset = self.windowOffset
let previousWindowCount = self.windowCount
let nextWindowOffset = max(0, self.windowOffset - self.pageSize)
let messagesNeeded = self.itemsOffset - nextWindowOffset
if messagesNeeded > 0 {
self.generateItems(messagesNeeded, position: .top)
}
let newItemsCount = previousWindowOffset - nextWindowOffset
self.windowOffset = nextWindowOffset
self.windowCount = previousWindowCount + newItemsCount
}
public func loadNext() {
guard !self.items.isEmpty else { return }
let itemCountAfterWindow = self.itemsOffset + self.items.count - self.windowOffset - self.windowCount
self.windowCount += min(self.pageSize, itemCountAfterWindow)
}
#discardableResult
public func adjustWindow(focusPosition: Double, maxWindowSize: Int) -> Bool {
assert(0 <= focusPosition && focusPosition <= 1, "")
guard 0 <= focusPosition && focusPosition <= 1 else {
assert(false, "focus should be in the [0, 1] interval")
return false
}
let sizeDiff = self.windowCount - maxWindowSize
guard sizeDiff > 0 else { return false }
self.windowOffset += Int(focusPosition * Double(sizeDiff))
self.windowCount = maxWindowSize
return true
}
#discardableResult
func replaceItem(withNewItem item: Element, where predicate: (Element) -> Bool) -> Bool {
guard let index = self.items.firstIndex(where: predicate) else { return false }
self.items[index] = item
return true
}
func contains(item: Element, where predicate: (Element) -> Bool ) -> Bool {
guard let _ = self.items.firstIndex(where: predicate) else { return false }
return true
}
//FIXME: Add delete method here, don't know the use off itemOffset, windowOffset, windowCount
// func delete(item: Element, where predicate: (Element) -> Bool ) {
// self.items.removeAll(where: predicate)
// }
}
I have raised a question in their Github repo. Here is the solution they answered.
when delete or add a new element in data source you need to -1 or +1 to offset. If offset is 0 - do nothing.
Originial answer link
I've got a set of properties/protocols (back story is here, but I think it's superfluous)
The class types look like this:
struct AdjustmentTypes {
internal class BaseType<T>: Hashable {
static func == (lhs: AdjustmentTypes.BaseType<T>, rhs: AdjustmentTypes.BaseType<T>) -> Bool {
return lhs.name == rhs.name
}
typealias A = T
var hashValue: Int { return name.hashValue }
let name: String
let defaultValue: T
let min: T
let max: T
var value: T
init(name: String, defaultValue: T, min: T, max: T) {
self.name = name
self.defaultValue = defaultValue
self.min = min
self.max = max
self.value = defaultValue
}
}
class FloatType: BaseType<CGFloat> { }
class IntType: BaseType<Int> { }
}
And I'm using type erasure to remove the type so I can store these in a Set, and I've built some helper methods to make my Set tooling simpler:
class AdjustmentsSet {
private var adjustmentsSet: Set<AnyHashable> = []
func insert(_ adjustment: AnyHashable) {
adjustmentsSet.insert(adjustment)
}
func remove(_ adjustment: AnyHashable) {
adjustmentsSet.remove(adjustment)
}
func contains(_ adjustment: AnyHashable) -> Bool {
return adjustmentsSet.contains(adjustment)
}
var count: Int { return adjustmentsSet.count }
}
var adjustmentsSet = AdjustmentsSet()
What I want to do now is add some helpers to my Set management class to be able to retrieve a property with the correct type, e.g. if I do:
let brightness = Brightness().make()
adjustments.get(brightness)
It should return nil, but if I do:
adjustments.insert(brightness)
adjustments.get(brightness)
I should now get the value back, as its correct type, AdjustmentTypes.FloatType.
I'm thinking to so something with a Switch statement like this:
class AdjustmentsSet {
// ...
func get(_ adjustment: AnyHashable) -> Any? {
guard let untyped = adjustmentsSet.first(where: { $0 == adjustment }) else { return nil }
switch adjustment {
case _ as AdjustmentTypes.FloatType: return untyped as! AdjustmentTypes.FloatType
case _ as AdjustmentTypes.IntType: return untyped as! AdjustmentTypes.IntType
default: return nil
}
}
}
However, the fatal flaw of course, is that this returns Any, instead of the intended type.
How can I infer the return value's type and to return the correct type?
Complete example, just drop this into a playground:
// Generic conforming protocol to AnyHashable
protocol AnyAdjustmentProtocol {
func make() -> AnyHashable
}
protocol AdjustmentProtocol: AnyAdjustmentProtocol {
associatedtype A
func make() -> A
}
struct AdjustmentTypes {
internal class BaseType<T>: Hashable {
static func == (lhs: AdjustmentTypes.BaseType<T>, rhs: AdjustmentTypes.BaseType<T>) -> Bool {
return lhs.name == rhs.name
}
typealias A = T
var hashValue: Int { return name.hashValue }
let name: String
let defaultValue: T
let min: T
let max: T
var value: T
init(name: String, defaultValue: T, min: T, max: T) {
self.name = name
self.defaultValue = defaultValue
self.min = min
self.max = max
self.value = defaultValue
}
}
class FloatType: BaseType<CGFloat> { }
class IntType: BaseType<Int> { }
}
struct AnyAdjustmentType<A>: AdjustmentProtocol, Hashable {
static func == (lhs: AnyAdjustmentType<A>, rhs: AnyAdjustmentType<A>) -> Bool {
return lhs.hashValue == rhs.hashValue
}
private let _make: () -> AnyHashable
private let hashClosure:() -> Int
var hashValue: Int {
return hashClosure()
}
init<T: AdjustmentProtocol & Hashable>(_ adjustment: T) where T.A == A {
_make = adjustment.make
hashClosure = { return adjustment.hashValue }
}
func make() -> AnyHashable {
return _make()
}
}
struct Brightness: AdjustmentProtocol, Hashable {
func make() -> AnyHashable {
return AdjustmentTypes.FloatType(name: "Brightness", defaultValue: 0, min: 0, max: 1)
}
}
struct WhiteBalance: AdjustmentProtocol, Hashable {
func make() -> AnyHashable {
return AdjustmentTypes.IntType(name: "White Balance", defaultValue: 4000, min: 3000, max: 7000)
}
}
let brightness = Brightness().make()
let whiteBalance = WhiteBalance().make()
class AdjustmentsSet {
private var adjustmentsSet: Set<AnyHashable> = []
func insert(_ adjustment: AnyHashable) {
adjustmentsSet.insert(adjustment)
}
func remove(_ adjustment: AnyHashable) {
adjustmentsSet.remove(adjustment)
}
func contains(_ adjustment: AnyHashable) -> Bool {
return adjustmentsSet.contains(adjustment)
}
var count: Int { return adjustmentsSet.count }
}
var adjustmentsSet = AdjustmentsSet()
You need to rewrite the method as a generic and call it with sufficient type information, i.e. you need to know in advance what type you expect the method to return.
I'm also not sure passing around AnyHashables is ideal anyway. Nothing stops you from adding Strings, Ints and other random types that are hashable to your adjustment set.
var adjustmentsSet = AdjustmentsSet()
adjustmentsSet.insert("1") // compiles just fine!
Alternatively, you could use and pass around your AdjustmentTypes and rewrite the AdjustmentsSet class with generic methods:
class AdjustmentsSet {
private var adjustmentsSet: Set<AnyHashable> = []
func insert<T>(_ adjustment: AdjustmentTypes.BaseType<T>) {
adjustmentsSet.insert(adjustment)
}
func remove<T>(_ adjustment: AdjustmentTypes.BaseType<T>) {
adjustmentsSet.remove(adjustment)
}
func contains<T>(_ adjustment: AdjustmentTypes.BaseType<T>) -> Bool {
return adjustmentsSet.contains(adjustment)
}
func get<T>(_ adjustment: AdjustmentTypes.BaseType<T>) -> AdjustmentTypes.BaseType<T>? {
return (adjustmentsSet.compactMap { $0 as? AdjustmentTypes.BaseType<T> }).first(where: { $0 == adjustment })
}
var count: Int { return adjustmentsSet.count }
}
Next, your make() methods should be more strongly typed as well, since you are not passing around AnyHashables. I implemented brightness and white balance like this:
extension AdjustmentTypes {
static let Brightness = AdjustmentTypes.FloatType(name: "Brightness", defaultValue: 0, min: 0, max: 1)
static let WhiteBalance = AdjustmentTypes.IntType(name: "White Balance", defaultValue: 4000, min: 3000, max: 7000)
}
And also took advantage of type aliases and structs in Swift, to make your adjustment type system behave with value semantics:
struct AdjustmentTypes {
struct BaseType<T>: Hashable {
static func == (lhs: AdjustmentTypes.BaseType<T>, rhs: AdjustmentTypes.BaseType<T>) -> Bool {
return lhs.name == rhs.name
}
typealias A = T
var hashValue: Int { return name.hashValue }
let name: String
let defaultValue: T
let min: T
let max: T
var value: T
init(name: String, defaultValue: T, min: T, max: T) {
self.name = name
self.defaultValue = defaultValue
self.min = min
self.max = max
self.value = defaultValue
}
}
typealias FloatType = BaseType<CGFloat>
typealias IntType = BaseType<Int>
}
Finally, you are able to use the adjustment set as intended:
var brightness = AdjustmentTypes.Brightness
brightness.value = 0.5
var adjustmentsSet = AdjustmentsSet()
adjustmentsSet.insert(brightness)
let retrievedBrightness = adjustmentsSet.get(AdjustmentTypes.Brightness)! // strongly typed!
retrievedBrightness.value // 0.5
AdjustmentTypes.Brightness.value // 0.0
The entire playground:
struct AdjustmentTypes {
struct BaseType<T>: Hashable {
static func == (lhs: AdjustmentTypes.BaseType<T>, rhs: AdjustmentTypes.BaseType<T>) -> Bool {
return lhs.name == rhs.name
}
typealias A = T
var hashValue: Int { return name.hashValue }
let name: String
let defaultValue: T
let min: T
let max: T
var value: T
init(name: String, defaultValue: T, min: T, max: T) {
self.name = name
self.defaultValue = defaultValue
self.min = min
self.max = max
self.value = defaultValue
}
}
typealias FloatType = BaseType<CGFloat>
typealias IntType = BaseType<Int>
}
extension AdjustmentTypes {
static let Brightness = AdjustmentTypes.FloatType(name: "Brightness", defaultValue: 0, min: 0, max: 1)
static let WhiteBalance = AdjustmentTypes.IntType(name: "White Balance", defaultValue: 4000, min: 3000, max: 7000)
}
class AdjustmentsSet {
private var adjustmentsSet: Set<AnyHashable> = []
func insert<T>(_ adjustment: AdjustmentTypes.BaseType<T>) {
adjustmentsSet.insert(adjustment)
}
func remove<T>(_ adjustment: AdjustmentTypes.BaseType<T>) {
adjustmentsSet.remove(adjustment)
}
func contains<T>(_ adjustment: AdjustmentTypes.BaseType<T>) -> Bool {
return adjustmentsSet.contains(adjustment)
}
func get<T>(_ adjustment: AdjustmentTypes.BaseType<T>) -> AdjustmentTypes.BaseType<T>? {
return (adjustmentsSet.compactMap { $0 as? AdjustmentTypes.BaseType<T> }).first(where: { $0 == adjustment })
}
var count: Int { return adjustmentsSet.count }
}
var brightness = AdjustmentTypes.Brightness
brightness.value = 0.5
var adjustmentsSet = AdjustmentsSet()
adjustmentsSet.insert(brightness)
let retrievedBrightness = adjustmentsSet.get(AdjustmentTypes.Brightness)! // strongly typed!
retrievedBrightness.value // 0.5
AdjustmentTypes.Brightness.value // 0.0
Hope this helps, good luck with your project!
I am trying to redevelop the Colony class I wrote for Conway's Game of Life with Sets instead of arrays but am having trouble doing so. Here's what I've got so far:
P.S. I am assuming a fixed Colony size of 20x20.
import Foundation
struct Array2DB {
var values: [Int]
var rows: Int
var cols: Int
init(rows: Int, cols: Int){
self.rows = rows
self.cols = cols
values = [Int](repeating: 0, count: (rows + 2) * (cols + 2) )
}
//allows uasge of the syntax [row, col] for get/set access
subscript(row:Int, col: Int) -> Int {
get {
return values[getIndex(row, col)]
}
set(val) {
values[getIndex(row, col)] = val
}
}
//converts 2D indices to index in data (terminates if out of bounds)
func getIndex(_ row: Int, _ col: Int) -> Int {
assert((row >= -1) && (row <= rows), "row \(row) is out of bounds")
assert((col >= -1) && (col <= cols), "col \(col) is out of bounds")
return (row + 1) * cols + col + 1
}
var description: String {
var desc = "Matrix:\n"
for row in 0 ..< rows {
for col in 0 ..< cols {
desc += " \(values[getIndex(row, col)]) "
}
desc += "\n"
}
return desc
}
}
class Colony: CustomStringConvertible {
let colony: Set = Array2DB[rows, cols, values]
func setCellAlive(xCoor: Int, yCoor: Int) {
colony[xCoor, yCoor] = 1
}
func setCellDead(xCoor:Int, yCoor: Int) {
colony[xCoor, yCoor] = 0
}
func resetColony() {
for i in 0..<colony.rows {
for e in 0..<colony.cols {
colony[i, e] = 0
}
}
}
var description: String {
var desc = ""
for i in 0..<colony.rows {
for e in 0..<colony.cols {
if colony[i, e] == 1 {
desc += "*"
} else {
desc += "-"
}
}
desc += "\n"
}
return desc
}
func isCellALive( xCoor: Int, yCoor: Int) -> Bool{
return colony[xCoor, yCoor] == 1
}
func evolve() {
var colonyUpdate: Array2DB = colony
for i in 0..<colony.rows {
for e in 0..<colony.cols {
let cGen = rules(xCoor: i, yCoor: e)
if ((cGen < 2) || (cGen > 3)) {
colonyUpdate[i, e] = 0
} else if cGen == 3 {
colonyUpdate[i, e] = 1
} else {
if colony[i, e] == 1 {
colonyUpdate[i, e] = 1
} else {
colonyUpdate[i, e] = 0
}
}
}
}
colony = colonyUpdate
}
}
I'm sure that I've implemented it wrong, but how would I turn the arrays to sets? I'm really confused and would appreciate any guidance or feedbac
Your data type Array2DB is not an Array. It is a Struct that contains an array. You can't assign an Array2DB to a variable that you've declared to be of type Set. It won't work.
You also can't use a Set as the storage for Conway's game of life. The Swift Set data type is an unordered collection. It is unsuitable to serve as the storage for the data in the game of life. You want an array, period.
A very little help for you to show an example of using Set in Game of Life.
struct Cell: Hashable {
var x: Int
var y: Int
}
class Colony: CustomStringConvertible {
var aliveCells: Set = Set<Cell>()
let numberOfRows: Int
let numberOfColumns: Int
init(colonySize: Int) {
self.numberOfRows = colonySize
self.numberOfColumns = colonySize
}
func setCellAlive(xCoor: Int, yCoor: Int) {
aliveCells.insert(Cell(x: xCoor, y: yCoor))
}
func setCellDead(xCoor:Int, yCoor: Int) {
aliveCells.remove(Cell(x: xCoor, y: yCoor))
}
func resetColony() {
aliveCells.removeAll(keepingCapacity: true)
}
var description: String {
var desc = ""
for i in 0..<numberOfRows {
for e in 0..<numberOfColumns {
if aliveCells.contains(Cell(x: e, y: i)) { //Usually `x` represents column, and `y` for row
desc += "*"
} else {
desc += "-"
}
}
desc += "\n"
}
return desc
}
//Implement other methods you need
//...
}
As already noted, Set is not a good data type for Game of Life. But you can implement it using Set. Good luck.
Can anyone tell me how to create a linked-list in swift with node as structure and linked-list as class.
I tried to create a node Node with reference to itself and faced a error "value type 'Node' cannot have a stored property that references itself"
for resolving it i created one more class Next
and now I am unable to proceed further.
You can not make node as a "struct" since Swift treats Struct and Enums as value types and Classes as reference type.
When you make the LinkedList Class you would very likely create a reference to your node structure. Now struct being a value type, capturing self for value types is dangerous practice and discouraged.
Therefore I would suggest you to create Node as Class and make use of the various access specifiers in Swift to achieve the abstraction you are trying to.
For more details on capturing self in value types you can refer to https://github.com/Wolox/ios-style-guide/blob/master/rules/avoid-struct-closure-self.md.
Details
Xcode 11.3.1, Swift 5.1
Base Interface
Nodeable protocol
import Foundation
protocol Nodeable: class {
associatedtype Value
var value: Value { get set }
var next: Self? { get set }
init(value: Value, next: Self?)
}
// MARK: Extensions
extension Nodeable where Self.Value: Equatable {
static func == (lhs: Self, rhs: Self) -> Bool { lhs.value == rhs.value }
}
extension Nodeable where Self: AnyObject {
var retainCount: Int { CFGetRetainCount(self as CFTypeRef) }
}
extension Nodeable where Self: CustomStringConvertible {
var description: String { return "{ value: \(value), next: \(next == nil ? "nill" : "exist") }" }
}
LinkedListable protocol
import Foundation
protocol LinkedListable where Node.Value == Value {
associatedtype Node: Nodeable
associatedtype Value
var firstNode: Node? { get set }
var lastNode: Node? { get set }
init()
}
extension LinkedListable {
var firstValue: Value? { return firstNode?.value }
var lastValue: Value? { return lastNode?.value }
var isEmpty: Bool { return firstNode == nil }
}
// MARK: Initializers
extension LinkedListable {
init(_ array: [Value]) {
self.init()
array.forEach { append(newLast: $0) }
}
init(copyValuesFrom linkedList: Self) {
self.init()
if linkedList.isEmpty { return }
linkedList.forEachNode { append(newLast: $0.value) }
}
init(copyReferencesFrom linkedList: Self) {
self.init()
firstNode = linkedList.firstNode
lastNode = linkedList.lastNode
}
}
// MARK: Iteration
extension LinkedListable {
func node(at index: Int) -> Node? {
if isEmpty { return nil }
var currentIndex = 0
var resultNode: Node?
forEachWhile {
if index == currentIndex { resultNode = $0; return false }
currentIndex += 1
return true
}
return resultNode
}
func forEachWhile(closure: (Node) -> (Bool)) {
var currentNode = self.firstNode
while currentNode != nil {
guard closure(currentNode!) else { return }
currentNode = currentNode?.next
}
}
func forEachNode(closure: (Node) -> ()) {
forEachWhile { closure($0); return true }
}
}
// MARK: Add/Get values
extension LinkedListable {
func value(at index: Int) -> Value? { node(at: index)?.value }
// MARK: Add new node to the end of list
mutating func append(newLast value: Value) {
let newNode = Node(value: value, next: nil)
if firstNode == nil {
firstNode = newNode
lastNode = firstNode
} else {
lastNode?.next = newNode
lastNode = lastNode?.next
}
}
}
LinkedListable protocol extensions
// MARK: CustomStringConvertible
extension LinkedListable where Self: CustomStringConvertible {
var description: String {
var values = [String]()
forEachNode { values.append("\($0.value)") }
return values.joined(separator: ", ")
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MARK: ExpressibleByArrayLiteral
extension LinkedListable where Self: ExpressibleByArrayLiteral, ArrayLiteralElement == Value {
init(arrayLiteral elements: Self.ArrayLiteralElement...) { self.init(elements) }
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MARK: Sequence
extension LinkedListable where Self: Sequence {
typealias Iterator = LinkedListableIterator<Node>
func makeIterator() -> LinkedListableIterator<Node> { return .init(firstNode) }
}
struct LinkedListableIterator<Node>: IteratorProtocol where Node: Nodeable {
private var currentNode: Node?
init(_ firstNode: Node?) { self.currentNode = firstNode }
mutating func next() -> Node.Value? {
let node = currentNode
currentNode = currentNode?.next
return node?.value
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MARK: Collection
extension LinkedListable where Self: Collection, Self.Index == Int, Self.Element == Value {
var startIndex: Index { 0 }
var endIndex: Index {
guard !isEmpty else { return 0 }
var currentIndex = 0
forEachNode { _ in currentIndex += 1 }
return currentIndex
}
func index(after i: Index) -> Index { i+1 }
subscript(position: Index) -> Element { node(at: position)!.value }
var isEmpty: Bool { return firstNode == nil }
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
extension LinkedListable where Self: MutableCollection, Self.Index == Int, Self.Element == Value {
subscript(position: Self.Index) -> Self.Element {
get { return node(at: position)!.value }
set(newValue) { node(at: position)!.value = newValue }
}
}
Usage
implementation of a Node class
import Foundation
final class LinkedListNode<Value>: Nodeable {
var value: Value
var next: LinkedListNode?
init(value: Value, next: LinkedListNode?) {
self.value = value
self.next = next
}
}
extension LinkedListNode: Equatable, CustomStringConvertible where Value: Equatable {}
Implementation of a List class (option 1)
class BaseLinkedList<Value>: LinkedListable where Value: Equatable {
typealias Node = LinkedListNode<Value>
var firstNode: LinkedListNode<Value>?
weak var lastNode: LinkedListNode<Value>?
required init() { }
}
Manipulations with List class (option 1)
var linkedList = BaseLinkedList(["one", "two", "three"])
linkedList = BaseLinkedList(copyReferencesFrom: linkedList)
linkedList = BaseLinkedList(copyValuesFrom: linkedList)
var node = linkedList.firstNode!
print("node value: \(node.value) \(String(describing: node.next))")
node = linkedList.lastNode!
print("node value: \(node.value) \(String(describing: node.next))")
print("isEmpty: \(linkedList.isEmpty)")
linkedList.append(newLast: "four")
linkedList.forEachNode { print($0.value) }
linkedList.forEachNode { print($0.value) }
print("node at index 3: \(String(describing: linkedList.node(at: 3)))")
print("value at index 5: \(String(describing: linkedList.value(at: 4)))")
Implementation of a List class (option 2)
class LinkedList<Value>: BaseLinkedList<Value> where Value: Equatable {}
extension LinkedList: CustomStringConvertible, ExpressibleByArrayLiteral, Sequence, Collection, MutableCollection {}
Manipulations with List class (option 2)
var linkedList = LinkedList(arrayLiteral: "one", "two", "three")
print(linkedList)
print(linkedList.map { $0 + "!" })
print(linkedList.reduce("", { "\($0)_\($1)" }))
linkedList[2] = "five"
print(linkedList[2])
print(linkedList.count)
Some unit tests
import XCTest
// MARK: Test basic List functionality
class TestBasicList: XCTestCase {
typealias LinkedList = BaseLinkedList<Int>
// typealias Value = Int
private var linkedList: LinkedList!
private var possibleValues: [LinkedList.Value] { [1, 2, 3, 4] }
override func setUp() { linkedList = LinkedList() }
func testInitListFromArray() {
TestBasicList.assertCollectionsContainsSameValues(linkedList: LinkedList(possibleValues), array: possibleValues)
}
func testInitListByCopyingValuesFromAnotherList() {
linkedList = .init(possibleValues)
let copiedLinkedList = LinkedList(copyValuesFrom: linkedList)
assertCollections(linkedList1: linkedList, linkedList2: copiedLinkedList, containEqualValues: true)
assertCollections(linkedList1: linkedList, linkedList2: copiedLinkedList, containsSameReferencesToNodes: false)
}
func testInitListByCopyingElementsReferencesFromAnotherList() {
linkedList = .init(possibleValues)
let copiedLinkedList = LinkedList(copyReferencesFrom: linkedList)
assertCollections(linkedList1: linkedList, linkedList2: copiedLinkedList, containEqualValues: true)
assertCollections(linkedList1: linkedList, linkedList2: copiedLinkedList, containsSameReferencesToNodes: true)
}
func testPushFunctionality() {
possibleValues.forEach { linkedList.append(newLast: $0) }
TestBasicList.assertCollectionsContainsSameValues(linkedList: linkedList, array: possibleValues)
}
func testRandomAccess() {
linkedList = .init(possibleValues)
(0 ..< possibleValues.count).forEach {
XCTAssertEqual(possibleValues[$0], linkedList.node(at: $0)?.value)
}
}
private func assertCollections(linkedList1: LinkedList, linkedList2: LinkedList, containEqualValues: Bool) {
var values1 = [LinkedList.Value]()
linkedList1.forEachNode { values1.append($0.value) }
var values2 = [LinkedList.Value]()
linkedList2.forEachNode { values2.append($0.value) }
if containEqualValues {
XCTAssertEqual(values1, values2)
} else {
XCTAssertNotEqual(values1, values2)
}
}
private func assertCollections(linkedList1: LinkedList, linkedList2: LinkedList, containsSameReferencesToNodes: Bool) {
var values1 = [LinkedList.Node]()
linkedList1.forEachNode { values1.append($0) }
var values2 = [LinkedList.Node]()
linkedList2.forEachNode { values2.append($0) }
var areSame: Bool!
for i in 0 ..< values1.count {
areSame = values1[i] === values2[i]
if containsSameReferencesToNodes {
XCTAssertTrue(areSame)
} else {
XCTAssertFalse(areSame)
}
}
}
}
extension TestBasicList {
class func assertCollectionsContainsSameValues<List: LinkedListable>(linkedList: List, array: [List.Value]) where List.Value: Equatable {
var values = [List.Value]()
linkedList.forEachNode { values.append($0.value) }
XCTAssertEqual(values, array)
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MARK: Sequence
class LinkedListSequence<Value>: BaseLinkedList<Value>, Sequence where Value: Equatable {}
protocol LinkedListSequenceTestable {
typealias Value = Int
typealias LinkedList = LinkedListSequence<Value>
var linkedList: LinkedList { get set }
var possibleValues: [Value] { get}
}
extension LinkedListSequenceTestable {
func _testFilter() {
XCTAssertEqual(linkedList.filter ({ $0 % 2 == 0 }),
possibleValues.filter({ $0 % 2 == 0 }))
}
func _testMap() {
guard let num = possibleValues.first else { return }
XCTAssertEqual(linkedList.map({ $0 + num}), possibleValues.map({ $0 + num}))
}
func _testCompactMap() {
let array1 = linkedList.compactMap { value -> String? in
if value % 2 != 0 { return "\(value)" }
return nil
}
let array2 = possibleValues.compactMap { value -> String? in
if value % 2 != 0 { return "\(value)" }
return nil
}
XCTAssertEqual(array1, array2)
}
func _testReduce() {
let result1 = linkedList.reduce(LinkedList.Element()) { $0 + $1 }
let result2 = possibleValues.reduce(LinkedList.Element()) { $0 + $1 }
XCTAssertEqual(result1, result2)
}
func _testForEach() {
var values1 = [LinkedList.Value]()
linkedList.forEach { values1.append($0) }
var values2 = [LinkedList.Value]()
possibleValues.forEach { values2.append($0) }
XCTAssertEqual(values1, values2)
}
}
class TestLinkedListSequence_nonEmpty: XCTestCase, LinkedListSequenceTestable {
var linkedList = LinkedList()
var possibleValues: [Value] { [1, 2, 3, 4] }
override func setUp() { linkedList = LinkedList(possibleValues) }
func testFilter() { _testFilter() }
func testMap() { _testMap() }
func testCompactMap() { _testCompactMap() }
func testReduce() { _testReduce() }
func testForEach() { _testForEach() }
}
class TestLinkedListSequence_oneElement: TestLinkedListSequence_nonEmpty {
override var possibleValues: [Value] { [1] }
}
class TestLinkedListSequence_empty: TestLinkedListSequence_nonEmpty {
override var possibleValues: [Value] { [] }
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MARK: Collection
class LinkedListCollection<Value>: BaseLinkedList<Value>, Sequence, Collection where Value: Equatable {}
protocol LinkedListCollectionTestable {
associatedtype Value: Equatable
typealias LinkedList = LinkedListCollection<Value>
var linkedList: LinkedList { get set }
var possibleValues: [Value] { get}
}
extension LinkedListCollectionTestable {
func _testCount() {
XCTAssertEqual(linkedList.count, possibleValues.count)
}
func _testIsEmpty() {
XCTAssertEqual(linkedList.isEmpty, possibleValues.isEmpty)
XCTAssertEqual(LinkedList().isEmpty, [].isEmpty)
}
func _testIndexes() {
for i in 0 ..< linkedList.count {
XCTAssertEqual(linkedList.index(after: i), possibleValues.index(after: i))
}
}
}
class TestLinkedListCollection_nonEmpty: XCTestCase, LinkedListCollectionTestable {
typealias LinkedList = LinkedListCollection<Int>
var linkedList = LinkedList()
var possibleValues: [LinkedList.Value] { [1, 2, 3, 4] }
override func setUp() { linkedList = LinkedList(possibleValues) }
func testCount() { _testCount() }
func testIsEmpty() { _testIsEmpty() }
func testIndexes() { _testIndexes() }
}
class TestLinkedListCollection_oneElement: TestLinkedListCollection_nonEmpty {
override var possibleValues: [LinkedList.Value] { [1] }
}
class TestLinkedListCollection_empty: TestLinkedListCollection_nonEmpty {
override var possibleValues: [LinkedList.Value] { [] }
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MARK: RangeReplaceableCollection
class LinkedListMutableCollection<Value>: BaseLinkedList<Value>, Sequence, Collection, MutableCollection where Value: Equatable & Comparable {}
protocol LinkedListMutableCollectionTestable {
associatedtype Value: Equatable & Comparable
typealias LinkedList = LinkedListMutableCollection<Value>
var linkedList: LinkedList { get set }
var possibleValues: [Value] { get}
}
extension LinkedListMutableCollectionTestable {
func _testSorted() {
XCTAssertEqual(linkedList.sorted(by: { $0 > $1 }),
possibleValues.sorted(by: { $0 > $1 }))
}
func _testSubscriptReading() {
for (index, value) in possibleValues.enumerated() {
XCTAssertEqual(linkedList[index], value)
}
}
func _testSubscriptWriting() {
var list = linkedList
var testArray = possibleValues
TestBasicList.assertCollectionsContainsSameValues(linkedList: linkedList, array: testArray)
for (index, value) in possibleValues.reversed().enumerated() {
testArray[index] = value
list[index] = value
XCTAssertEqual(linkedList[index], testArray[index])
}
print(testArray)
TestBasicList.assertCollectionsContainsSameValues(linkedList: linkedList, array: testArray)
}
}
class TestLinkedListMutableCollection_nonEmptyCollection: XCTestCase, LinkedListMutableCollectionTestable {
typealias LinkedList = LinkedListMutableCollection<Int>
var linkedList = LinkedList()
var possibleValues: [LinkedList.Value] { [1, 3, 2, 4] }
override func setUp() { linkedList = LinkedList(possibleValues) }
func testSorted() { _testSorted() }
func testSubscriptReading() { _testSubscriptReading() }
func testSubscriptWriting() { _testSubscriptWriting() }
}
class TestLinkedListMutableCollection_oneElement: TestLinkedListMutableCollection_nonEmptyCollection {
override var possibleValues: [LinkedList.Value] { [1] }
}
class TestLinkedListMutableCollection_empty: TestLinkedListMutableCollection_nonEmptyCollection {
override var possibleValues: [LinkedList.Value] { [] }
}
Custom LinkedList Type
Xcode 10.2.1, Swift 5.0
My LinkedList type implements all of the following protocols:
CustomStringConvertible
ExpressibleByArrayLiteral
Sequence
Collection
MutableCollection
RangeReplaceableCollection
BidirectionalCollection
As well, it keeps its node type private so the user never needs to know anything of its existence.
This implementation is a doubly linked list so to efficiently enable bidirectional traversal.
Code:
public struct LinkedList<Element> {
private var headNode: Node?
private var tailNode: Node?
public private(set) var count: Int = 0
private var id = ID()
public init() { }
fileprivate class ID {
init() { }
}
}
//MARK: - LinkedList Node
extension LinkedList {
fileprivate class Node {
public var value: Element
public var next: Node?
public weak var previous: Node?
public init(value: Element) {
self.value = value
}
}
}
//MARK: - Initializers
public extension LinkedList {
private init(_ nodeChain: (head: Node, tail: Node, count: Int)?) {
guard let chain = nodeChain else {
return
}
headNode = chain.head
tailNode = chain.tail
count = chain.count
}
init<S>(_ sequence: S) where S: Sequence, S.Element == Element {
if let linkedList = sequence as? LinkedList<Element> {
self = linkedList
} else {
self = LinkedList(chain(of: sequence))
}
}
}
//MARK: Chain of Nodes
extension LinkedList {
// Creates a chain of nodes from a sequence. Returns `nil` if the sequence is empty.
private func chain<S>(of sequence: S) -> (head: Node, tail: Node, count: Int)? where S: Sequence, S.Element == Element {
var iterator = sequence.makeIterator()
var head, tail: Node
var count = 0
guard let firstValue = iterator.next() else {
return nil
}
var currentNode = Node(value: firstValue)
head = currentNode
count = 1
while let nextElement = iterator.next() {
let nextNode = Node(value: nextElement)
currentNode.next = nextNode
nextNode.previous = currentNode
currentNode = nextNode
count += 1
}
tail = currentNode
return (head: head, tail: tail, count: count)
}
}
//MARK: - Copy Nodes
extension LinkedList {
private mutating func copyNodes(settingNodeAt index: Index, to value: Element) {
var currentIndex = startIndex
var currentNode = Node(value: currentIndex == index ? value : currentIndex.node!.value)
let newHeadNode = currentNode
currentIndex = self.index(after: currentIndex)
while currentIndex < endIndex {
let nextNode = Node(value: currentIndex == index ? value : currentIndex.node!.value)
currentNode.next = nextNode
nextNode.previous = currentNode
currentNode = nextNode
currentIndex = self.index(after: currentIndex)
}
headNode = newHeadNode
tailNode = currentNode
}
#discardableResult
private mutating func copyNodes(removing range: Range<Index>) -> Range<Index> {
id = ID()
var currentIndex = startIndex
while range.contains(currentIndex) {
currentIndex = index(after: currentIndex)
}
guard let headValue = currentIndex.node?.value else {
self = LinkedList()
return endIndex..<endIndex
}
var currentNode = Node(value: headValue)
let newHeadNode = currentNode
var newCount = 1
var removedRange: Range<Index> = Index(node: currentNode, offset: 0, id: id)..<Index(node: currentNode, offset: 0, id: id)
currentIndex = index(after: currentIndex)
while currentIndex < endIndex {
guard !range.contains(currentIndex) else {
currentIndex = index(after: currentIndex)
continue
}
let nextNode = Node(value: currentIndex.node!.value)
if currentIndex == range.upperBound {
removedRange = Index(node: nextNode, offset: newCount, id: id)..<Index(node: nextNode, offset: newCount, id: id)
}
currentNode.next = nextNode
nextNode.previous = currentNode
currentNode = nextNode
newCount += 1
currentIndex = index(after: currentIndex)
}
if currentIndex == range.upperBound {
removedRange = Index(node: nil, offset: newCount, id: id)..<Index(node: nil, offset: newCount, id: id)
}
headNode = newHeadNode
tailNode = currentNode
count = newCount
return removedRange
}
}
//MARK: - Computed Properties
public extension LinkedList {
var head: Element? {
return headNode?.value
}
var tail: Element? {
return tailNode?.value
}
}
//MARK: - Sequence Conformance
extension LinkedList: Sequence {
public typealias Element = Element
public __consuming func makeIterator() -> Iterator {
return Iterator(node: headNode)
}
public struct Iterator: IteratorProtocol {
private var currentNode: Node?
fileprivate init(node: Node?) {
currentNode = node
}
public mutating func next() -> Element? {
guard let node = currentNode else {
return nil
}
currentNode = node.next
return node.value
}
}
}
//MARK: - Collection Conformance
extension LinkedList: Collection {
public var startIndex: Index {
return Index(node: headNode, offset: 0, id: id)
}
public var endIndex: Index {
return Index(node: nil, offset: count, id: id)
}
public var first: Element? {
return head
}
public var isEmpty: Bool {
return count == 0
}
public func index(after i: Index) -> Index {
precondition(i.listID === self.id, "LinkedList index is invalid")
precondition(i.offset != endIndex.offset, "LinkedList index is out of bounds")
return Index(node: i.node?.next, offset: i.offset + 1, id: id)
}
public struct Index: Comparable {
fileprivate weak var node: Node?
fileprivate var offset: Int
fileprivate weak var listID: ID?
fileprivate init(node: Node?, offset: Int, id: ID) {
self.node = node
self.offset = offset
self.listID = id
}
public static func ==(lhs: Index, rhs: Index) -> Bool {
return lhs.offset == rhs.offset
}
public static func <(lhs: Index, rhs: Index) -> Bool {
return lhs.offset < rhs.offset
}
}
}
//MARK: - MutableCollection Conformance
extension LinkedList: MutableCollection {
public subscript(position: Index) -> Element {
get {
precondition(position.listID === self.id, "LinkedList index is invalid")
precondition(position.offset != endIndex.offset, "Index out of range")
guard let node = position.node else {
preconditionFailure("LinkedList index is invalid")
}
return node.value
}
set {
precondition(position.listID === self.id, "LinkedList index is invalid")
precondition(position.offset != endIndex.offset, "Index out of range")
// Copy-on-write semantics for nodes
if !isKnownUniquelyReferenced(&headNode) {
copyNodes(settingNodeAt: position, to: newValue)
} else {
position.node?.value = newValue
}
}
}
}
//MARK: LinkedList Specific Operations
public extension LinkedList {
mutating func prepend(_ newElement: Element) {
replaceSubrange(startIndex..<startIndex, with: CollectionOfOne(newElement))
}
mutating func prepend<S>(contentsOf newElements: __owned S) where S: Sequence, S.Element == Element {
replaceSubrange(startIndex..<startIndex, with: newElements)
}
#discardableResult
mutating func popFirst() -> Element? {
if isEmpty {
return nil
}
return removeFirst()
}
#discardableResult
mutating func popLast() -> Element? {
if isEmpty {
return nil
}
return removeLast()
}
}
//MARK: - BidirectionalCollection Conformance
extension LinkedList: BidirectionalCollection {
public var last: Element? {
return tail
}
public func index(before i: Index) -> Index {
precondition(i.listID === self.id, "LinkedList index is invalid")
precondition(i.offset != startIndex.offset, "LinkedList index is out of bounds")
if i.offset == count {
return Index(node: tailNode, offset: i.offset - 1, id: id)
}
return Index(node: i.node?.previous, offset: i.offset - 1, id: id)
}
}
//MARK: - RangeReplaceableCollection Conformance
extension LinkedList: RangeReplaceableCollection {
public mutating func append<S>(contentsOf newElements: __owned S) where S: Sequence, Element == S.Element {
replaceSubrange(endIndex..<endIndex, with: newElements)
}
public mutating func replaceSubrange<S, R>(_ subrange: R, with newElements: __owned S) where S: Sequence, R: RangeExpression, Element == S.Element, Index == R.Bound {
var range = subrange.relative(to: indices)
precondition(range.lowerBound.listID === id && range.upperBound.listID === id, "LinkedList range of indices are invalid")
precondition(range.lowerBound >= startIndex && range.upperBound <= endIndex, "Subrange bounds are out of range")
// If range covers all elements and the new elements are a LinkedList then set references to it
if range.lowerBound == startIndex, range.upperBound == endIndex, let linkedList = newElements as? LinkedList {
self = linkedList
return
}
var newElementsCount = 0
// There are no new elements, so range indicates deletion
guard let nodeChain = chain(of: newElements) else {
// If there is nothing in the removal range
// This also covers the case that the linked list is empty because this is the only possible range
guard range.lowerBound != range.upperBound else {
return
}
// Deletion range spans all elements
if range.lowerBound == startIndex && range.upperBound == endIndex {
headNode = nil
tailNode = nil
count = 0
return
}
// Copy-on-write semantics for nodes and remove elements in range
guard isKnownUniquelyReferenced(&headNode) else {
copyNodes(removing: range)
return
}
// Update count after mutation to preserve startIndex and endIndex validity
defer {
count = count - (range.upperBound.offset - range.lowerBound.offset)
}
// Move head up if deletion starts at start index
if range.lowerBound == startIndex {
// Can force unwrap node since the upperBound is not the end index
headNode = range.upperBound.node!
headNode!.previous = nil
// Move tail back if deletion ends at end index
} else if range.upperBound == endIndex {
// Can force unwrap since lowerBound index must have an associated element
tailNode = range.lowerBound.node!.previous
tailNode!.next = nil
// Deletion range is in the middle of the linked list
} else {
// Can force unwrap all bound nodes since they both must have elements
range.upperBound.node!.previous = range.lowerBound.node!.previous
range.lowerBound.node!.previous!.next = range.upperBound.node!
}
return
}
// Obtain the count of the new elements from the node chain composed from them
newElementsCount = nodeChain.count
// Replace entire content of list with new elements
if range.lowerBound == startIndex && range.upperBound == endIndex {
headNode = nodeChain.head
tailNode = nodeChain.tail
count = nodeChain.count
return
}
// Copy-on-write semantics for nodes before mutation
if !isKnownUniquelyReferenced(&headNode) {
range = copyNodes(removing: range)
}
// Update count after mutation to preserve startIndex and endIndex validity
defer {
count += nodeChain.count - (range.upperBound.offset - range.lowerBound.offset)
}
// Prepending new elements
guard range.upperBound != startIndex else {
headNode?.previous = nodeChain.tail
nodeChain.tail.next = headNode
headNode = nodeChain.head
return
}
// Appending new elements
guard range.lowerBound != endIndex else {
tailNode?.next = nodeChain.head
nodeChain.head.previous = tailNode
tailNode = nodeChain.tail
return
}
if range.lowerBound == startIndex {
headNode = nodeChain.head
}
if range.upperBound == endIndex {
tailNode = nodeChain.tail
}
range.lowerBound.node!.previous!.next = nodeChain.head
range.upperBound.node!.previous = nodeChain.tail
}
}
//MARK: - ExpressibleByArrayLiteral Conformance
extension LinkedList: ExpressibleByArrayLiteral {
public typealias ArrayLiteralElement = Element
public init(arrayLiteral elements: ArrayLiteralElement...) {
self.init(elements)
}
}
//MARK: - CustomStringConvertible Conformance
extension LinkedList: CustomStringConvertible {
public var description: String {
return "[" + lazy.map { "\($0)" }.joined(separator: ", ") + "]"
}
}
//MARK: - Equatable Conformance
extension LinkedList: Equatable where Element: Equatable {
public static func ==(lhs: LinkedList<Element>, rhs: LinkedList<Element>) -> Bool {
for (a, b) in zip(lhs, rhs) {
guard a == b else {
return false
}
}
return true
}
}
If you'd like to use this type fully-documented in your own project, feel free to download it or add it as a dependency with Swift PM by checking out my LinkedList GitHub repository.
This is not really a good question for Stack Overflow, but I will answer anyway. Here is a super basic implementation of a singly linked list:
class Node {
let value: Int
var next: Node?
init(value: Int, next: Node? = nil) {
self.value = value
self.next = next
}
}
class LinkedList {
let head: Node
init(node: Node) {
self.head = node
}
convenience init(nodeValue: Int) {
self.init(node: Node(value: nodeValue))
}
func addNode(node: Node) {
var current: Node = self.head
while current.next != nil {
current = current.next!
}
current.next = node
}
func addNode(withValue value: Int) {
self.addNode(node: Node(value: value))
}
}
let list = LinkedList(nodeValue: 4)
list.addNode(withValue: 3)
list.addNode(withValue: 8)
//The list is now [ 4 ]->[ 3 ]->[ 8 ]
Hopefully I can clarify a few points.
Can anyone tell me how to create a linked-list in swift with node as
structure and linked-list as class.
The node essentially is the structure. As other people have pointed out, a linked list is nothing more than a very basic data type (often called a Node) that holds a value and a reference to another Node.
The code posted above is a linked list:
class Node {
let value: Int
var next: Node?
init(value: Int, next: Node? = nil) {
self.value = value
self.next = next
}
}
Think of a link in a chain. This is your Node.
Think of a couple of links together. This is your linked list.
My point here is that there is nothing additional. By having the ability to make a single Node, you have the ability to make a linked list (just a bunch of Nodes connected).
I tried to create a node Node with reference to itself and faced a
error "value type 'Node' cannot have a stored property that references
itself"
Others have explained why this won't work.
for resolving it i created one more class Next and now I am unable to
proceed further.
Please don't do this. Your next node is just another Node. This is completely unnecessary.
Sometimes you will see a linked list class that holds a Node. This is just to help you manipulate the list a little easier. So when you say
linked-list as class
I'm pretty sure you're just referring to a collection of functions that help manipulate your list. These can just as easily be standalone functions that take a Node and operate on it.
For instance to add a link to the chain you can have a function add(value: Value, to list: Node). A function like this may or may not exist on some arbitrary LinkedList class. It often does but probably should not.
func append(_ node: Node, to list: Node) {
var current = list
while let nextNode = current.next {
current = nextNode
}
current.next = node
}
Hope this helps!
Checked on XCode 10 playground - Swift 4.2
class Node {
let value: Int
var next: Node?
init(value: Int, next: Node? = nil) {
self.value = value
self.next = next
}
}
class LinkedList {
let head: Node
init(node: Node) {
self.head = node
}
convenience init(nodeValue: Int) {
self.init(node: Node(value: nodeValue))
}
func addNode(node: Node) {
var current: Node = self.head
while current.next != nil {
current = current.next!
}
current.next = node
}
func addNode(withValue value: Int) {
self.addNode(node: Node(value: value))
}
func traverse() -> [Int]{
var results: [Int] = []
var current: Node = self.head
while current.next != nil {
current = current.next!
results.append(current.value)
}
return results
}
}
let list = LinkedList(nodeValue: 4)
list.addNode(withValue: 3)
list.addNode(withValue: 8)
list.addNode(withValue: 8)
list.addNode(withValue: 8)
list.addNode(withValue: 8)
list.traverse()
A workaround that I can think of is to describe the linked list node as a protocol and then create a struct that confirms that protocol
protocol LinkedNode {
var value: Int { get }
var next: LinkedListNode? { get }
}
struct Node: LinkedNode {
let value: Int
let next: LinkedListNode?
}
let linkedList = Node(value: 2, next: Node(value: 4, next: nil))
I am trying to create a recursive Swift implementation for the solution of the classic puzzle: "How can we distribute n queens on a chess grid of n × n so that no queen can threaten another".
With existing code I encountered the following problems:
Code does not produce all the solutions for n<=8
Code does not product ANY solution for n>=9
Can't seem to compare solutions for n=8 (8x8) and larger because I compute the hash for each Solution class (board) by shifting bits which represent existence of queen or empty tile:
public override var hash: Int {
var hash = 0
for i in 0...self.board.count-1 {
for j in 0...self.board.count-1 {
if self.board[i][j].state == .Queen {
hash |= 1
hash <<= 1
} else {
hash <<= 1
}
}
}
return hash
}
when board is >8x8 value gets corrupted as it is larger than 64 bits (swift Int is Int64). What's a good solution for that?
My current code:
import UIKit
public typealias Board = Array<Array<Cell>>
#objc protocol QueenPlacementDelegate : class {
func solutionsFound(numOfSolutions : Int)
}
class QueenPlacement: NSObject {
var boardView : TTTBoardView?
var boardSize : Int = 0
var solutions : Set<Solution>?
weak var delegate : QueenPlacementDelegate?
private var startCondX : Int = 0
private var startCondY : Int = 0
func start() {
if boardSize == 0 {
print("Board size was not initialized")
return
}
self.solutions = Set<Solution>()
var done = false
self.startCondX = 0; self.startCondY = 0;
while (!done) {
let solution = Solution(boardSize: self.boardSize)
let board = solution.board
self.placeQueen(startCondX, yLoc: startCondY, board: board)
let solutionBoard = self.findSolutionForBoard(board)
if self.numOfQueensOnBoard(solutionBoard) == self.boardSize {
print("solution found")
solution.board = solutionBoard
self.solutions!.insert(solution)
}
done = self.advanceStartConditionsAndCheckIfDone()
if (done) {
if self.solutions!.count > 0 {
self.delegate!.solutionsFound(self.solutions!.count)
}
}
}
}
func advanceStartConditionsAndCheckIfDone() -> Bool {
startCondX++
if startCondX >= self.boardSize {
startCondX = 0
startCondY++
if startCondY >= self.boardSize {
return true
}
}
return false
}
func placeQueen(xLoc : Int, yLoc : Int, board : Board) {
board[xLoc][yLoc].state = .Queen
}
func findSolutionForBoard(board : Board) -> Board
{
let queensPlaced = self.numOfQueensOnBoard(board)
if queensPlaced == self.boardSize {
return board
}
else
{
for i in 0...self.boardSize-1 {
for j in 0...self.boardSize-1 {
if self.canPlaceQueen(xLoc: i, yLoc: j, board: board) {
self.placeQueen(i, yLoc: j, board: board)
}
}
}
let newQueensPlaced = self.numOfQueensOnBoard(board)
// recursion exit conditions: could not place any new queen
if newQueensPlaced > queensPlaced {
self.findSolutionForBoard(board)
} else {
return board
}
}
return board
}
func numOfQueensOnBoard(board : Board) -> Int {
var queensPlaced = 0
for i in 0...self.boardSize-1 {
for j in 0...self.boardSize-1 {
if board[i][j].state == .Queen {
queensPlaced++
}
}
}
return queensPlaced
}
func canPlaceQueen(xLoc xLoc : Int, yLoc : Int, board: Board) -> Bool {
for i in 0...self.boardSize-1 {
if board[i][yLoc].state == .Queen {
return false;
}
if board[xLoc][i].state == .Queen {
return false;
}
}
var x : Int
var y : Int
x = xLoc; y = yLoc;
while ++x < self.boardSize && ++y < self.boardSize {
if board[x][y].state == .Queen {
return false
}
}
x = xLoc; y = yLoc;
while --x >= 0 && ++y < self.boardSize {
if board[x][y].state == .Queen {
return false
}
}
x = xLoc; y = yLoc;
while ++x < self.boardSize && --y >= 0 {
if board[x][y].state == .Queen {
return false
}
}
x = xLoc; y = yLoc;
while --x >= 0 && --y >= 0 {
if board[x][y].state == .Queen {
return false
}
}
return true
}
// singleton!
static let sharedInstance = QueenPlacement()
private override init() {}
}
What is wrong here?
P.S.
for easier reading - full code repo can be found here
It's not an answer in a way that I don't know what is the problem with your version, but here is another one (looks working as I tested it), a little bit simplier (based on Scala By Example - The N-Queens Problem).
func queens(n: Int) -> [[Int]] {
guard n > 3 else {
return [[Int]]()
}
func placeQueens(k: Int) -> [[Int]] {
guard k > 0 else {
return [[-1]] //stupid hack to let the app go to the for-loop in the * marked place
}
var res = [[Int]]()
for var q in placeQueens(k - 1) { //* marked place
if let first = q.first where first == -1 { //this is for removing the hacky -1
q.removeAll()
}
for column in 1...n {
if isSafe(column, queens: q) {
var solution = q
solution.append(column)
res.append(solution)
}
}
}
return res
}
return placeQueens(n)
}
func isSafe(column: Int, queens: [Int]) -> Bool {
for (index, q) in queens.enumerate() {
let dy = (index + 1) - (queens.count + 1)
let dx = q - column
let isDiagonal = dy * dy == dx * dx
if q == column || isDiagonal {
return false
}
}
return true
}
And if you want to draw the solutions out:
func drawTable(table: [Int]) -> String {
var res = ""
table.forEach {
for column in 1...table.count {
if $0 == column {
res += "X "
} else {
res += ". "
}
}
res += "\n"
}
return res
}
And
queens(4).forEach {
print(drawTable($0))
}
Computing the 73712 solutions of n = 13 took some minutes, above that you would probably run out of memory this way.