BSON for Swift? - swift

My question's pretty open ended at this point, but I'm curious if anyone has implemented something like SwiftyJSON for BSON in Swift?
I found that the Perfect project has something, but it seems to just be a wrapper around an existing C library (won't do me any good on the iOS side). I toyed with just porting/warping SwiftyJSON, the internals of which are a little above my learning curve so far AND it seems to just be a wrapper around the platform's JSONSerialization.
So is anyone either
A) aware of something done that my googling hasn't discovered yet or
B) or could help nudge me in the right direction with how to generally architect such a thing? (not trying to get others to do work for me)
aside: to forestall the "why don't you just use json" questions... it's because I'm doing quite a bit of MongoDB on the other side AND I work with a lot of Strings and Dates, which have to be ambiguously represented in JSON

In the interest of closure... I ended up writing my own. It is not a complete solution to all of the BSON encodings, just the ones that I'm using. It was fun to figure out how to do it with Swift Enums.
import Foundation
extension GeneratorType {
mutating func next(n: Int) -> [Element] {
var result: [Element] = []
for _ in 1...n {
if let next = self.next() {
result.append(next)
} else {
break
}
}
return result
}
}
extension GeneratorType where Element:Comparable {
mutating func upTo(match:Element) -> [Element]? {
var result: [Element] = []
while let next = self.next() {
if next == match {
return result
}
else {
result.append(next)
}
}
return nil
}
}
extension String {
init?<S : SequenceType, C : UnicodeCodecType where S.Generator.Element == C.CodeUnit>
(codeUnits : S, inout codec : C) {
var str = ""
var generator = codeUnits.generate()
var done = false
while !done {
let r = codec.decode(&generator)
switch (r) {
case .EmptyInput:
done = true
case let .Result(val):
str.append(Character(val))
case .Error:
return nil
}
}
self = str
}
}
enum BSON {
static func toByteArray<T>(value: T) -> [UInt8] {
var io = value
return withUnsafePointer(&io) {
Array(UnsafeBufferPointer(start: UnsafePointer<UInt8>($0), count: sizeof(T)))
}
}
static func fromByteArray<T>(value: [UInt8], _: T.Type) -> T {
return value.withUnsafeBufferPointer {
return UnsafePointer<T>($0.baseAddress).memory
}
}
struct Field {
var name:String
var element:BSON
}
case double(Double)
case string(String)
case document([Field])
case array([BSON])
case binary([UInt8])
// case objectid((UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8))
case boolean(Bool)
case datetime(NSDate)
case null
case int32(Int32)
case int64(Int64)
init() {
self = .document([])
}
var bsonType:UInt8 {
switch self {
case .double: return 0x01
case .string: return 0x02
case .document: return 0x03
case .array: return 0x04
case .binary: return 0x05
// case .objectid: return 0x07
case .boolean: return 0x08
case .datetime: return 0x09
case .null: return 0x0A
case .int32: return 0x10
case .int64: return 0x12
}
}
subscript(key:String) -> BSON {
get {
switch self {
case .document (let fields):
for field in fields {
if field.name == key {
return field.element
}
}
return BSON.null
default:
return BSON.null
}
}
set(newValue) {
var newFields:[Field] = []
switch self {
case .document (let fields):
newFields = fields
var append = true
for (index, field) in newFields.enumerate() {
if field.name == key {
newFields[index].element = newValue
append = false
break
}
}
if append {
newFields.append(Field(name: key, element: newValue))
}
default:
newFields = [Field(name: key, element: newValue)]
}
self = .document(newFields)
}
}
subscript(index:Int) -> BSON {
get {
switch self {
case .array (let elements):
return index < elements.count ? elements[index] : BSON.null
default:
return BSON.null
}
}
set(newValue) {
switch self {
case .array (let elements):
if index < elements.count {
var newElements = elements
newElements[index] = newValue
self = .array(newElements)
}
default:
break
}
}
}
func encoded() -> [UInt8] {
switch self {
case double (let value):
return BSON.toByteArray(value)
case string (let value):
let encoded = value.utf8
return BSON.toByteArray(Int32(encoded.count + 1)) + encoded + [0]
case document (let fields):
var body:[UInt8] = []
for field in fields ?? [] {
body += [field.element.bsonType]
body += field.name.utf8
body += [0]
body += field.element.encoded()
}
body += [0]
return BSON.toByteArray(Int32(body.count + 4)) + body
case array (let elements):
var body:[UInt8] = []
for (index, element) in elements.enumerate() {
body += [element.bsonType]
body += String(index).utf8
body += [0]
body += element.encoded()
}
body += [0]
return BSON.toByteArray(Int32(body.count + 4)) + body
case binary (let bytes):
return BSON.toByteArray(Int32(bytes.count)) + [0x00] + bytes
// case objectid:
// return []
case boolean (let value):
return value ? [0x01] : [0x00]
case datetime (let value):
let since = Int64(value.timeIntervalSince1970 * 1000.0)
return BSON.toByteArray(since)
case null:
return []
case int32 (let value):
return BSON.toByteArray(value)
case int64 (let value):
return BSON.toByteArray(value)
}
}
static func decode(inout stream stream:IndexingGenerator<[UInt8]>, bsonType:UInt8 = 0x03) -> BSON {
switch bsonType {
case 0x01:
let bytes = stream.next(sizeof(Double))
return self.double(fromByteArray(bytes, Double.self))
case 0x02:
let _ = stream.next(sizeof(Int32)) // skip the count
if let buffer = stream.upTo(0) {
var codec = UTF8()
if let decoded = String(codeUnits: buffer, codec: &codec) {
return self.string(decoded)
}
}
fatalError("utf8 parse error!")
case 0x03:
var fields:[Field] = []
stream.next(sizeof(Int32)) // throw out size
while let bsonType = stream.next() {
if bsonType == 0 {
return self.document(fields)
}
if let buffer = stream.upTo(0) {
var codec = UTF8()
if let fieldName = String(codeUnits: buffer, codec: &codec) {
let element = BSON.decode(stream:&stream, bsonType: bsonType)
fields.append(Field(name: fieldName, element: element))
}
}
}
case 0x04:
var elements:[BSON] = []
stream.next(sizeof(Int32)) // throw out size
while let bsonType = stream.next() {
if bsonType == 0 {
return self.array(elements)
}
stream.upTo(0) // skip name
elements.append(BSON.decode(stream:&stream, bsonType: bsonType))
}
case 0x05:
let count = fromByteArray(stream.next(sizeof(Int32)), Int32.self)
assert(stream.next() == 0x00)
return self.binary(stream.next(Int(count)))
case 0x07:
break
case 0x08:
let value = stream.next()
return self.boolean(value == 0x01)
case 0x09:
let milliseconds = fromByteArray(stream.next(sizeof(Int64)), Int64.self)
let interval = NSTimeInterval(milliseconds) / 1000.0
return self.datetime(NSDate(timeIntervalSince1970: interval))
case 0x0A:
return self.null
case 0x10:
let value = fromByteArray(stream.next(sizeof(Int32)), Int32.self)
return self.int32(value)
case 0x12:
let value = fromByteArray(stream.next(sizeof(Int64)), Int64.self)
return self.int64(value)
default:
break
}
fatalError()
}
var document:BSON? {
switch self {
case .document:
return self
default:
return nil
}
}
var double:Double? {
switch self {
case .double (let value):
return value
default:
return nil
}
}
var int32:Int32? {
get {
switch self {
case .int32 (let value):
return value
default:
return nil
}
}
set {
if let newValue = newValue {
self = .int32(newValue)
}
else {
self = .null
}
}
}
var int64:Int64? {
switch self {
case .int64 (let value):
return value
default:
return nil
}
}
var boolean:Bool? {
switch self {
case .boolean (let value):
return value
default:
return nil
}
}
var binary:[UInt8]? {
switch self {
case .binary (let value):
return value
default:
return nil
}
}
var string:String? {
switch self {
case .string (let value):
return value
default:
return nil
}
}
var datetime:NSDate? {
switch self {
case .datetime (let value):
return value
default:
return nil
}
}
var array:[BSON]? {
switch self {
case .array (let elements):
return elements
default:
return nil
}
}
var isNull:Bool {
switch self {
case .null:
return true
default:
return false
}
}
var keyValues:[(String, BSON)] {
switch self {
case document (let fields):
return fields.map() { ($0.name, $0.element) }
default:
return []
}
}
}
extension BSON: Equatable {}
extension BSON.Field: Equatable {}
func == (a:BSON.Field, b:BSON.Field) -> Bool {
return a.name == b.name && a.element == b.element
}
func == (a:BSON, b:BSON) -> Bool {
switch (a, b) {
case (.double(let a), .double(let b)) where a == b: return true
case (.string(let a), .string(let b)) where a == b: return true
case (.document(let a), .document(let b)) where a == b: return true
case (.array(let a), .array(let b)) where a == b: return true
case (.binary(let a), .binary(let b)) where a == b: return true
case (.boolean(let a), .boolean(let b)) where a == b: return true
case (.datetime(let a), .datetime(let b)) where a.isEqualToDate(b): return true
case (.null, .null): return true
case (.int32(let a), .int32(let b)) where a == b: return true
case (.int64(let a), .int64(let b)) where a == b: return true
default: return false
}
}
protocol BSONConvertable {
var bson:BSON { get }
}
extension Int32: BSONConvertable {
var bson:BSON {
return BSON.int32(self)
}
}
extension Int64: BSONConvertable {
var bson:BSON {
return BSON.int64(self)
}
}
extension Int: BSONConvertable {
var bson:BSON {
let wide = self.toIntMax()
if Int32.min.toIntMax() <= wide && wide <= Int32.max.toIntMax() {
return BSON.int32(Int32(wide))
}
else {
return BSON.int64(Int64(wide))
}
}
}
extension Float:BSONConvertable {
var bson:BSON {
return Double(self).bson
}
}
extension Double:BSONConvertable {
var bson:BSON {
return BSON.double(self)
}
}
extension Bool:BSONConvertable {
var bson:BSON {
return BSON.boolean(self)
}
}
extension BSON:BSONConvertable {
var bson:BSON {
return self
}
}
extension NSDate:BSONConvertable {
var bson:BSON {
return BSON.datetime(self)
}
}
extension String:BSONConvertable {
var bson:BSON {
return BSON.string(self)
}
}
extension Array where Element:BSONConvertable {
var bson:BSON {
return BSON.array(self.map({$0.bson}))
}
}

Late to the party but the OpenKitten implementation on github seems to be a good implementation and it is referenced from the BSON spec site.
https://github.com/OpenKitten/BSON

Related

How does Storing Failable Results for Later / trailing closure syntax to call Result(catching:) work in Swift?

Within chapter on error handling there is an example on expression evaluator and code on storing Failable Results for Later - code below, lines after implementation of function evaluate. This part does throw more errors, would like to ask if you can help to clarify these. I am going back from the beggining of the book again, checking sources and practicing more examples. Still appreciate your help, so when comming back can study it more.
enum Token: CustomStringConvertible {
case number (Int)
case plus
var description: String {
switch self {
case .number (let n):
return "Number: \(n)"
case .plus:
return "Symbol: +"
}
}
}
class Lexer {
enum Error: Swift.Error {
case invalidCharacter (Character)
}
let input: String
var position: String.Index
init(input: String) {
self.input = input
self.position = input.startIndex
}
func peek() -> Character? {
guard position < input.endIndex else {
return nil
}
return input[position]
}
func advance() {
assert(position < input.endIndex, "Cannot advance past endIndex!")
position = input.index(after: position)
}
func getNumber() -> Int {
var value = 0
while let nextCharacter = peek() {
switch nextCharacter {
case "0" ... "9":
let digitValue = Int(String(nextCharacter))!
value = 10*value + digitValue
advance()
default:
return value
}
}
return value
}
func lex() throws -> [Token] {
var tokens = [Token]()
while let nextCharacter = peek() {
switch nextCharacter {
case "0" ... "9":
let value = getNumber()
tokens.append(.number(value))
case "+":
tokens.append(.plus)
advance()
case " ":
advance()
default:
throw Lexer.Error.invalidCharacter(nextCharacter)
}
}
return tokens
}
}
func evaluate(_ input: String) {
print("Evaluating: \(input)")
let lexer = Lexer(input: input)
do {
let tokens = try lexer.lex()
print("Lexer output: \(tokens)")
let parser = Parser(tokens: tokens)
let result = try parser.parse()
print("Parser output: \(result)")
} catch Lexer.Error.invalidCharacter(let character) {
print("Input contained an invalid character: \(character)")
} catch Parser.Error.unexpectedEndOfInput {
print("Unexpected end of input during parsing")
} catch Parser.Error.invalidToken(let token) {
print("Invalid token during parsing: \(token)")
} catch {
print("An error occured: \(error)")
}
}
class Parser {
enum Error: Swift.Error {
case unexpectedEndOfInput
case invalidToken(Token)
}
let tokens: [Token]
var position = 0
init(tokens: [Token]) {
self.tokens = tokens
}
func getNextToken() -> Token? {
guard position < tokens.count else {
return nil
}
let token = tokens[position]
position += 1
return token
}
func getNumber() throws -> Int {
guard let token = getNextToken() else {
throw Parser.Error.unexpectedEndOfInput
}
switch token {
case .number(let value):
return value
case .plus:
throw Parser.Error.invalidToken(token)
}
}
func parse() throws -> Int {
var value = try getNumber()
while let token = getNextToken() {
switch token {
case .plus:
let nextNumber = try getNumber()
value += nextNumber
case .number:
throw Parser.Error.invalidToken(token)
}
}
return value
}
}
evaluate("10 + 1")
// below is code on Storing Failable Results for Later:
let lexer = Lexer(input: "1 + 3 + 3 + 7")
let tokensResult = Result { try lexer.lex() } // Result<Success, Failure>' cannot be constructed because it has no accessible initializers
enum Result<Success, Failure> where Failure : Error {
case .success(Success) // Extraneous '.' in enum 'case' declaration
case .failure(Failure) // Extraneous '.' in enum 'case' declaration
}
switch tokensResult {
case let .success(tokens):
print("Found \(tokens.count) tokens \(tokens)")
case let .failure(error):
print("Could not lex \(lexer.input): \(error)")
}
let numbersResult: Result<[Int],Error> = tokensResult.map {
tokens.compactMap { token in // Cannot find 'tokens' in scope
switch token {
case let .number(digit): return digit
default: return nil
}
}
}
func extractNumbers(from result: Result<[Int],Error>) throws -> [Int] {
return try result.get() // Value of type 'Result<[Int], Error>' has no member 'get'
}

Storing Generic Objects in a Heterogeneous Array and retrieving object parameter as the correct type

Ahoy everyone,
I have recently been trying to implement a Node based graph system that passes data between nodes using plugs. Similar to many of the 3D applications like houdini and maya.
I have written a similar system before using Python, and wanted to try this with Swift as my first learning excersise. Boy did I jump into the deep end on this one.
I am stuck now with Swifts Arrays, as I would like to store a list of Generic plugs.
Each plug can have its own value type float, int, color, string, Vector Matrix.
I have read up about Type Erasers and opaque types, but still cant seem to get my values our of a list in a way that I can perform some arithmetic on them.
All and any help that might put me in the direction would be greatly appreciated :D
import Foundation
import MetalKit
protocol genericPlug {
associatedtype T
func GetValue() -> T
}
class Plug<T>:genericPlug{
var _value:T?
var value:T {
get{GetValue()}
set(val){
value = val
}
}
func GetValue() -> T{
return _value!
}
init(_ newValue:T){
_value=newValue
}
}
class Node{
var plugs:[genericPlug] = []
init(){
var p1 = Plug<Int>(0)
var p2 = Plug(vector2(1.2, 3.1))
var p3 = Plug([0.0, 3.1, 0.6, 1])
plugs.append(p1)
plugs.append(p2)
plugs.append(p3)
}
func execute(){
// will access the plugs in the array and perform some sort of calculations on them.
plugs[0].value + 1 // should equal 1
plugs[1].value.x + 0.8 // should have x=2.0 y=3.1
plugs[2].value[1] - 0.1 // should equal 3.0
}
}
Thanks everyone
Use a generic something to extract what you need. Your options are methods and subscripts.
protocol PlugValue {
init()
}
extension Int: PlugValue { }
extension Float: PlugValue { }
extension Double: PlugValue { }
extension SIMD3: PlugValue where Scalar == Int32 { }
struct Plug<Value: PlugValue> {
var value: Value
init(_ value: Value) {
self.value = value
}
}
protocol AnyPlug {
var anyValue: PlugValue { get }
}
extension AnyPlug {
subscript<Value: PlugValue>(type: Value.Type = Value.self) -> Value {
anyValue as? Value ?? .init()
}
func callAsFunction<Value: PlugValue>(_ type: Value.Type = Value.self) -> Value {
anyValue as? Value ?? .init()
}
}
extension Plug: AnyPlug {
var anyValue: PlugValue { value }
}
let plugs: [AnyPlug] = [
Plug(1),
Plug(2.3 as Float),
Plug(4.5),
Plug([6, 7, 8] as SIMD3)
]
plugs[0][Int.self] // 1
plugs[1][Double.self] // 0
plugs[1][] as Float // 2.3
let double: Double = plugs[2]() // 4.5
plugs[3](SIMD3.self).y // 7
With the array of protocols, do you have to down cast them into their Plug when retrieving them every time?
Essentially. This is true of all heterogenous sequences. Here are your options:
extension Array: PlugValue where Element: PlugValue { }
let plug: AnyPlug = Plug([0.1, 1.1, 2.1])
(plug as? Plug<[Double]>)?.value[1]
(plug.anyValue as? [Double])?[1]
extension Plug {
enum Error: Swift.Error {
case typeMismatch
}
}
extension AnyPlug {
func callAsFunction<Value: PlugValue, Return>(_ closure: (Value) -> Return) throws {
guard let value = anyValue as? Value
else { throw Plug<Value>.Error.typeMismatch }
closure(value)
}
}
try plug { (doubles: [Double]) in doubles[1] } // 1.1
try plug { ($0 as [Double])[1] } // 1.1
try plug { $0 as Int } // <Swift.Int>.Error.typeMismatch
I managed to find a solution that worked for my needs.
I am still looking at finding a better way to handle getting the data and their correct type.
import Foundation
import MetalKit
// Creating the PlugType Enum
enum PlugType{
case Integer(Int?)
case Float_(Float?)
case Double_(Double?)
case Vector3(simd_int3)
// default types
static func IntegerType() -> PlugType{ return PlugType.Integer(nil)}
static func FloatType() -> PlugType{ return PlugType.Float_(nil)}
static func DoubleType() -> PlugType{ return PlugType.Double_(nil)}
}
// Implements a way to retrieve the correct value type
extension PlugType{
var IntegerValue: Int{
switch self{
case .Integer(let value):
return value ?? 0
default:
return 0
}
}
var FloatValue: Float{
switch self
{
case .Float_(let value):
return value ?? 0
default:
return 0
}
}
var DoubleValue: Double{
switch self
{
case .Double_(let value):
return value ?? 0
default:
return 0
}
}
}
// Get the string representation of the PlugType
extension PlugType {
var typeName: String{
switch self {
case .Integer: return "Integer"
case .Float_: return "Float"
case .Double_: return "Double"
case .Vector3: return "Vector3"
}
}
var swiftType: Any.Type {
switch self {
case .Integer: return Int.self
case .Float_: return Float.self
case .Double_: return Double.self
case .Vector3: return simd_int3.self
}
}
}
class Plug{
var _value:PlugType?
var type:String? { get{ return _value?.typeName } }
init(_ newValue:PlugType){
_value = newValue
}
func geee<T>(_ input:T) -> T{
switch type {
case "Integer":
return getVal(_value!.IntegerValue) as! T
case "Double":
return getVal(_value!.DoubleValue) as! T
default:
return 0 as! T
}
}
func getVal(_ val:Int) -> Int {
return val
}
func getVal(_ val:Float) -> Float {
return val
}
func getVal(_ val:Double) -> Double {
return val
}
}
var plugs:[Plug] = []
var p1 = Plug(PlugType.Integer(2))

Enum pattern matching as a parameter to a function call

I've setup a playground with an example:
enum CarType : Equatable {
case wheeled(wheels: Int)
case flying
public static func ==(lhs: CarType, rhs: CarType) -> Bool {
return lhs.enumName == rhs.enumName
}
var enumName: String {
let stuff = "\(self)".split(separator: "(").first!
return String(describing: stuff)
}
}
var typesPresentAtMyParty = [CarType.wheeled(wheels:4), .wheeled(wheels:4), .flying]
let aKnownType = CarType.flying
if case aKnownType = typesPresentAtMyParty[2] {
print("Was the type")
}
func isPresent(type: CarType, inArray: [CarType]) -> Bool {
return inArray.filter {
if case type = $0 {
return true
}
return false
}.first != nil
}
func isWheeled(inArray: [CarType]) -> Bool {
return inArray.filter {
if case .wheeled = $0 {
return true
}
return false
}.first != nil
}
isPresent(type: .flying, inArray: typesPresentAtMyParty)
isPresent(type: .wheeled, inArray: typesPresentAtMyParty)
The last line here does not compile. While i can do if case .wheeled = $0 ignoring associated type as a check, i cannot find a way of doing the same in a function call isPresent(type: CarType, inArray: [CarType]), when sending isPresent(type: .wheeled, inArray: typesPresentAtMyParty)
Is there a way of writing a function that takes only the valid pattern matching part of the enum as a parameter?
It is not possible to pass partially constructed enums to a function. Partially constructed enums are not valid values, and they only work in pattern matching because the compiler has a concrete value to work with - the one from the right side of the pattern.
These being said, you could easily rewrite your functions to better, more swiftier versions.
Firstly, you don't need isPresent, you can simply use contains:
typesPresentAtMyParty.contains { $0 == .flying }
typesPresentAtMyParty.contains { if case . wheeled = $0 { return true } else { return false } }
Similarly, isWheeled can be shortened (and renamed, for better semantics):
func isWheeled(_ carType: CarType) -> Bool {
if case . wheeled = carType { return true } else { return false }
}
which can pe passed to contains:
let hasWeeled = typesPresentAtMyParty.contains(where: isWheeled)

How to check for palindrome in Swift using recursive definition

I like many of the features in Swift, but using manipulating strings are still a big pain in the ass.
func checkPalindrome(word: String) -> Bool {
print(word)
if word == "" {
return true
} else {
if word.characters.first == word.characters.last {
return checkPalindrome(word.substringWithRange(word.startIndex.successor() ..< word.endIndex.predecessor()))
} else {
return false
}
}
}
This code fails miserably whenever the string's length is an odd number. Of course I could make it so the first line of the block would be if word.characters.count < 2, but is there a way in Swift to get substrings and check easily?
Update
I like many of the suggestions, but I guess the original question could be misleading a little, since it's a question about String more than getting the right results for the function.
For instance, in Python, checkPalindrome(word[1:-1]) would work fine for the recursive definition, whereas Swift code is much less graceful since it needs other bells and whistles.
return word == String(word.reversed())
func isPalindrome(myString:String) -> Bool {
let reverseString = String(myString.characters.reversed())
if(myString != "" && myString == reverseString) {
return true
} else {
return false
}
}
print(isPalindrome("madam"))
I have used the below extension to find whether the number is Palindrome or Not.
extension String {
var isPalindrome: Bool {
return self == String(self.reversed())
}
}
Sometimes having a front end for a recursion can simplify life. I sometimes do this when the arguments which are most convenient to use are not what I want in the user interface.
Would the following meet your needs?
func checkPalindrome(str: String) -> Bool {
func recursiveTest(var charSet: String.CharacterView) -> Bool {
if charSet.count < 2 {
return true
} else {
if charSet.popFirst() != charSet.popLast() {
return false
} else {
return recursiveTest(charSet)
}
}
}
return recursiveTest(str.characters)
}
just add on more condition in if
func checkPalindrome(word: String) -> Bool {
print(word)
if (word == "" || word.characters.count == 1){
return true
}
else {
if word.characters.first == word.characters.last {
return checkPalindrome(word.substringWithRange(word.startIndex.successor() ..< word.endIndex.predecessor()))
} else {
return false
}
}
}
extension StringProtocol where Self: RangeReplaceableCollection {
var letters: Self { filter(\.isLetter) }
var isPalindrome: Bool {
let letters = self.letters
return String(letters.reversed()).caseInsensitiveCompare(letters) == .orderedSame
}
}
"Dammit I'm Mad".isPalindrome // true
"Socorram-me subi no onibus em marrocos".isPalindrome // true
You can also break your string into an array of characters and iterate through them until its half comparing one by one with its counterpart:
func checkPalindrome(_ word: String) -> Bool {
let chars = Array(word.letters.lowercased())
for index in 0..<chars.count/2 {
if chars[index] != chars[chars.count - 1 - index] {
return false
}
}
return true
}
And the recursive version fixing the range issue where can't form a range with endIndex < startIndex:
func checkPalindrome<T: StringProtocol>(_ word: T) -> Bool {
let word = word.lowercased()
.components(separatedBy: .punctuationCharacters).joined()
.components(separatedBy: .whitespacesAndNewlines).joined()
if word == "" || word.count == 1 {
return true
} else {
if word.first == word.last {
let start = word.index(word.startIndex,offsetBy: 1, limitedBy: word.endIndex) ?? word.startIndex
let end = word.index(word.endIndex,offsetBy: -1, limitedBy: word.startIndex) ?? word.endIndex
return checkPalindrome(word[start..<end])
} else {
return false
}
}
}
checkPalindrome("Dammit I'm Mad")
I think if you make an extension to String like this one then it will make your life easier:
extension String {
var length: Int { return characters.count }
subscript(index: Int) -> Character {
return self[startIndex.advancedBy(index)]
}
subscript(range: Range<Int>) -> String {
return self[Range<Index>(start: startIndex.advancedBy(range.startIndex), end: startIndex.advancedBy(range.endIndex))]
}
}
With it in place, you can change your function to this:
func checkPalindrome(word: String) -> Bool {
if word.length < 2 {
return true
}
if word.characters.first != word.characters.last {
return false
}
return checkPalindrome(word[1..<word.length - 1])
}
Quick test:
print(checkPalindrome("aba")) // Prints "true"
print(checkPalindrome("abc")) // Prints "false"
extension String {
func trimmingFirstAndLastCharacters() -> String {
guard let startIndex = index(self.startIndex, offsetBy: 1, limitedBy: self.endIndex) else {
return self
}
guard let endIndex = index(self.endIndex, offsetBy: -1, limitedBy: self.startIndex) else {
return self
}
guard endIndex >= startIndex else {
return self
}
return String(self[startIndex..<endIndex])
}
var isPalindrome: Bool {
guard count > 1 else {
return true
}
return first == last && trimmingFirstAndLastCharacters().isPalindrome
}
}
We first declare a function that removes first and last characters from a string.
Next we declare a computer property which will contain the actual recursive code that checks if a string is palindrome.
If string's size is less than or equal 1 we immediately return true (strings composed by one character like "a" or the empty string "" are considered palindrome), otherwise we check if first and last characters of the string are the same and we recursively call isPalindrome on the current string deprived of the first and last characters.
Convert the string into an Array. When the loop is executed get the first index and compare with the last index.
func palindrome(string: String)-> Bool{
let char = Array(string)
for i in 0..<char.count / 2 {
if char[i] != char[char.count - 1 - i] {
return false
}
}
return true
}
This solution is not recursive, but it is a O(n) pure index based solution without filtering anything and without creating new objects. Non-letter characters are ignored as well.
It uses two indexes and walks outside in from both sides.
I admit that the extension type and property name is stolen from Leo, I apologize. 😉
extension StringProtocol where Self: RangeReplaceableCollection {
var isPalindrome : Bool {
if isEmpty { return false }
if index(after: startIndex) == endIndex { return true }
var forward = startIndex
var backward = endIndex
while forward < backward {
repeat { formIndex(before: &backward) } while !self[backward].isLetter
if self[forward].lowercased() != self[backward].lowercased() { return false }
repeat { formIndex(after: &forward) } while !self[forward].isLetter
}
return true
}
}
Wasn't really thinking of this, but I think I came up with a pretty cool extension, and thought I'd share.
extension String {
var subString: (Int?) -> (Int?) -> String {
return { (start) in
{ (end) in
let startIndex = start ?? 0 < 0 ? self.endIndex.advancedBy(start!) : self.startIndex.advancedBy(start ?? 0)
let endIndex = end ?? self.characters.count < 0 ? self.endIndex.advancedBy(end!) : self.startIndex.advancedBy(end ?? self.characters.count)
return startIndex > endIndex ? "" : self.substringWithRange(startIndex ..< endIndex)
}
}
}
}
let test = ["Eye", "Pop", "Noon", "Level", "Radar", "Kayak", "Rotator", "Redivider", "Detartrated", "Tattarrattat", "Aibohphobia", "Eve", "Bob", "Otto", "Anna", "Hannah", "Evil olive", "Mirror rim", "Stack cats", "Doom mood", "Rise to vote sir", "Step on no pets", "Never odd or even", "A nut for a jar of tuna", "No lemon, no melon", "Some men interpret nine memos", "Gateman sees name, garageman sees nametag"]
func checkPalindrome(word: String) -> Bool {
if word.isEmpty { return true }
else {
if word.subString(nil)(1) == word.subString(-1)(nil) {
return checkPalindrome(word.subString(1)(-1))
} else {
return false
}
}
}
for item in test.map({ $0.lowercaseString.stringByReplacingOccurrencesOfString(",", withString: "").stringByReplacingOccurrencesOfString(" ", withString: "") }) {
if !checkPalindrome(item) {
print(item)
}
}
A simple solution in Swift:
func isPalindrome(word: String) -> Bool {
// If no string found, return false
if word.count == 0 { return false }
var index = 0
var characters = Array(word) // make array of characters
while index < characters.count / 2 { // repeat loop only for half length of given string
if characters[index] != characters[(characters.count - 1) - index] {
return false
}
index += 1
}
return true
}
func checkPalindrome(_ inputString: String) -> Bool {
if inputString.count % 2 == 0 {
return false
} else if inputString.count == 1 {
return true
} else {
var stringCount = inputString.count
while stringCount != 1 {
if inputString.first == inputString.last {
stringCount -= 2
} else {
continue
}
}
if stringCount == 1 {
return true
} else {
return false
}
}
}

Binary tree implementation using Swift enum

I'm doing some experiments with Swift enums to become more familiarized with them and have implemented a rudimentary binary tree. It works when adding up to three items, but adding more beyond that doesn't change it and I couldn't see why it wasn't working.
Here's the code:
protocol TreeProtocol {
mutating func insert(value: Int)
func walk()
}
enum Tree:TreeProtocol {
case Empty
case Leaf(Int)
case Node(Int, TreeProtocol?, TreeProtocol?)
init(){
self = .Empty;
}
init(value: Int) {
self = .Leaf(value)
}
init(value: Int, left:TreeProtocol?, right:TreeProtocol?){
self = .Node(value, left, right);
}
mutating func insert(value: Int) {
switch self {
case .Empty:
self = .Leaf(value)
case .Leaf(let currentNodeValue):
let newTree = Tree(value: value) // var here generates a warning
if value < currentNodeValue {
self = .Node(currentNodeValue, newTree, .None)
}
else {
self = .Node(currentNodeValue, .None, newTree)
}
case let .Node(currentNodeValue, leftNode, rightNode):
if (value < currentNodeValue) {
if leftNode == nil {
let newTree = Tree(value: value)
self = .Node(currentNodeValue, newTree, rightNode)
}
else {
var l = leftNode! // unable to call leftNode!.insert() directly
l.insert(value)
}
}
else {
if rightNode == nil {
let newTree = Tree(value: value)
self = .Node(currentNodeValue, leftNode, newTree)
}
else {
var r = rightNode!
r.insert(value)
}
}
}
}
func walk() {
switch self {
case .Empty:
print("Empty")
case .Leaf (let value):
print("\(value), ")
case .Node(let value, let leftNode, let rightNode):
if leftNode != nil {
leftNode!.walk()
}
print("\(value) ")
if (rightNode != nil) {
rightNode!.walk()
}
}
}
}
And if I run the following tests:
var tree = Tree();
tree.walk()
tree.insert(100)
tree.walk()
tree.insert(50)
tree.walk()
tree.insert(150)
tree.walk()
tree.insert(25)
tree.walk()
The output is:
Empty
100
50,
100
50,
100,
150
50,
100,
150
The 25 value is not getting added to the tree
(This code is a bit inelegant, its just the first iteration, there's several ugly parts in there that could be improved and beautified. Waiting for recursive enum functionality to be added to the Xcode beta).
Because you're mutating the internal nodes and that is actually creating a copy of them. That copy is never inserted into the tree, it's just thrown away after being modified. If after inserting into l and r you reinsert those nodes (with self = .Node(currentNodeValue, l, rightNode) and self = .Node(currentNodeValue, leftNode, r) respectively) then the tree as a whole will get updated. It's a by-value / by-reference issue.
I know you already have an answer, but I really like your implementation and thought I'd provide the code for implementing #Wain's solution and also streamline some of the nested if-else logic.
It involves a slight modification for the protocol, so that insert returns a value:
protocol TreeProtocol {
mutating func insert(value: Int) -> TreeProtocol
func walk()
}
And then the insert function can be rewritten like this:
mutating func insert(value: Int) -> TreeProtocol {
switch self {
case .Empty:
self = .Leaf(value)
case .Leaf(let currentNodeValue):
let newTree = Tree(value: value)
self = value < currentNodeValue
? .Node(currentNodeValue, newTree, .None)
: .Node(currentNodeValue, .None, newTree)
case var .Node(currentNodeValue, leftNode, rightNode):
self = value < currentNodeValue
? .Node(currentNodeValue, leftNode?.insert(value) ?? Tree(value: value), rightNode)
: .Node(currentNodeValue, leftNode, rightNode?.insert(value) ?? Tree(value: value))
}
return self
}