Sorting mixed String-Int Strings numerically as the primary order, then alphabetically in swift - swift

For a String which have both String and Int values (one of each) is it possible to do simple sort that will give the items ordered in numerical order as the primary order and alphabetical as the secondary order
var nameArray = ["Dave7", "Bob8", "Cathy9", "Henry10", "Susan10", "Pat11", "Steve12", "Dan12", "Ken1", "Sean2", "Howard3", "Dixie3", "Newman5", "Billy6"]
var sortedNameArray = nameArray.sort { $0.compare($1, options: .NumericSearch) == .OrderedAscending }
print(sortedNameArray) // gives the following:
Don't want this -> ["Billy6", "Bob8", "Cathy9", "Dan12", "Dave7", "Dixie3", "Henry10", "Howard3", "Ken1", "Newman5", "Pat11", "Sean2", "Steve12", "Susan10"]
Even though .NumericSearch was used the result is alphabetical.
I was able to get the desired result using a custom binary tree. Which gives the results:
Ken1 Sean2 Dixie3 Howard3 Newman5 Billy6 Dave7 Bob8 Cathy9 Henry10 Susan10 Pat11 Dan12 Steve12
But is there a simpler solution?
extension String {
var integerValue: Int? {
return Int(self)
}
}
func extractValueFromString(theString:String)->Int{
var catNumber: [Character] = []
//print("theString \(theString)")
for character in theString.characters{
var characterString = String(character)
if var value = characterString.integerValue { //if we don't check program crashes
//if numberSet.contains(Int(String(character))!) { //another way to check but redundant here
catNumber.append(character)
//print(catNumber)
// }
}
}
let numberString = String(catNumber)
return Int(numberString)!
}
class Node{
//nodes now only arrange strings
var data = ""
var value = Int()
var left:Node?;
var right:Node?;
deinit {
//print("deleting \(data)")
// print("node deleted")
}
init(data:String){
self.data = data;
//print(data)
}
}
class binaryTreeSort{
var root:Node?
init(){
}
deinit {
//print("tree deleted")
}
func getRoot()->Node{
return root!
}
func insertNewValue(data:String){
let newNode = Node(data:data)
var node:Node? = root
if (node == nil){
root = newNode
}
while (node != nil) {
let currentValue = node?.data
if currentValue == ""{
node?.data = data
return
}
if currentValue == data {
//we don't want duplicates.
return
}
if extractValueFromString(currentValue!) < extractValueFromString(data) {
if (node!.right != nil) {
node = node!.right
//print("Going Right at data \(node!.data)")
}else{
node!.right = newNode
//print("Going New Right at data \(node!.data)")
return
}
}else if extractValueFromString(currentValue!) == extractValueFromString(data){
if currentValue < data {
if (node!.right != nil) {
node = node!.right
//print("Going Right at data \(node!.data)")
}else{
node!.right = newNode
//print("Going New Right at data \(node!.data)")
return
}
}else{
if (node!.left != nil) {
//print("Going Left at data \(node!.data)")
node = node!.left
}else{
node!.left = newNode
//print("Going New Left at data \(node!.data)")
return
}
}
}
else{
if (node!.left != nil) {
//print("Going Left at data \(node!.data)")
node = node!.left
}else{
node!.left = newNode
//print("Going New Left at data \(node!.data)")
return
}
}
}
}
func inorderPrint(baseNode:Node){
if(baseNode.left != nil)
{
inorderPrint(baseNode.left!);
//print(" \(baseNode.data)")
}
print("\(baseNode.data)")
if(baseNode.right != nil)
{
inorderPrint(baseNode.right!)
//print(" \(baseNode.data)")
}
}
func reverseOrderPrint(baseNode:Node){
if(baseNode.right != nil)
{
reverseOrderPrint(baseNode.right!)
//print(" \(baseNode.data)")
}
print("\(baseNode.data)")
if(baseNode.left != nil)
{
reverseOrderPrint(baseNode.left!);
//print(" \(baseNode.data)")
}
}
}
var myBinaryTreeSort:binaryTreeSort? = binaryTreeSort()
for item in nameArray{
//print(item)
myBinaryTreeSort!.insertNewValue(item)
}
myBinaryTreeSort!.inorderPrint(myBinaryTreeSort!.getRoot())
print("---------------")
myBinaryTreeSort!.reverseOrderPrint(myBinaryTreeSort!.getRoot())
myBinaryTreeSort = nil //delete the tree

Use map to split the names into parts, sort to sort by number and name, and then map to restore the original:
func splitName(name:String) -> (String, Int) {
if let range = name.rangeOfCharacterFromSet(NSCharacterSet.decimalDigitCharacterSet()) {
return (name[name.startIndex..<range.startIndex], Int(name[range.startIndex..<name.endIndex])!)
} else {
return (name, 0)
}
}
print(nameArray.map(splitName).sort({ lhs, rhs in
if lhs.1 < rhs.1 {
return true
} else if lhs.1 > rhs.1 {
return false
} else {
return lhs.0 < rhs.0
}
}).map({ "\($0.0)\($0.1)" }))
Some other ways it could be done would be to maintain element 0 of the tuple as the full name (with numbers) and then the final map just becomes map({ $0.0 }) Depending on sizes, this may be more optimal than splitting the name each time it's compared.

If you have an array, you can sort with a custom closure.
For example:
nameArray.sort({extractValueFromString($0) < extractValueFromString($1)})
Will get you close. You just need to check if they are equal and return $0 < $1 instead.

Here's how I solved this, doing something similar to what #Lou-Franco alluded to:
func endInteger(word: String) -> Int {
if let range = word.rangeOfCharacterFromSet(NSCharacterSet.decimalDigitCharacterSet()){
let numberSubstring = word.substringFromIndex(range.startIndex)
return Int(numberSubstring) ?? 0
}
return 0
}
let sortedArray = yourArray.sort{endInteger($1) > endInteger($0)}

Related

How I can correctly combine items in section with RxDataSource swift?

I need to combine chat message in section when items send in one minutes.
ViewModel
.....
.scan([MessageSectionModel]()) { sectionModels, messageItem in
var models = sectionModels
if let lastSectionModel = sectionModels.last {
switch lastSectionModel {
case .incomingSection(var items):
if messageItem.0.isIncoming {
items.append(messageItem.0)
models[models.count-1] = .incomingSection(items: items)
} else {
models.append(.outcomingSection(items: [messageItem.0]))
}
case .outcomingSection(var items):
if messageItem.0.isIncoming {
models.append(.incomingSection(items: [messageItem.0]))
} else {
items.append(messageItem.0)
models[models.count-1] = .outcomingSection(items: items)
}
}
return models
}
if messageItem.0.isIncoming {
models.append(.incomingSection(items: [messageItem.0]))
} else {
models.append(.outcomingSection(items: [messageItem.0]))
}
return models
}
.....
ViewController
....
#IBOutlet private weak var messagesTableView: UITableView!
private let disposeBag = DisposeBag()
private var dataSource: RxTableViewSectionedAnimatedDataSource<MessageSectionModel>!
private let messageHeaderReuseIdentifier = String(describing: MessageHeaderView.self)
private let messageFooterReuseIdentifier = String(describing: MessageFooterView.self)
dataSource = RxTableViewSectionedAnimatedDataSource<MessageSectionModel>(
animationConfiguration: .init(insertAnimation: .none, reloadAnimation: .none, deleteAnimation: .none),
configureCell: { dataSource, tableView, indexPath, item in
switch dataSource.sectionModels[indexPath.section] {
case .incomingSection:
guard let cell = tableView.dequeueReusableCell(
withIdentifier: R.reuseIdentifier.incomingMessageTableViewCell,
for: indexPath
) else {
return UITableViewCell()
}
let isFirst = indexPath.row == dataSource[indexPath.section].items.count - 1
cell.bind(
messageText: item.text,
isFirstInSection: isFirst
)
return cell
case .userSection:
guard let cell = tableView.dequeueReusableCell(
withIdentifier: R.reuseIdentifier.outcomingMessageTableViewCell,
for: indexPath
) else {
return UITableViewCell()
}
cell.bind(
messageText: item.text,
isFirstInSection: indexPath.row == dataSource[indexPath.section].items.count - 1
)
return cell
}
})
....
Message items
....
import Foundation
import RxDataSources
enum MessageSectionModel {
case incomingSection(items: [MessageSectionItem])
case outcomingSection(items: [MessageSectionItem])
var lastMessageDate: Date {
switch self {
case .incomingSection(let items):
return items.last?.sentDate ?? Date()
case .outcomingSection(let items):
return items.last?.sentDate ?? Date()
}
}
}
struct MessageSectionItem {
let userId: String
let id: String = UUID().uuidString
let text: String
let sentDate: Date
let isIncoming: Bool
}
extension MessageSectionItem: IdentifiableType {
var identity : String {
return id
}
}
extension MessageSectionItem: Equatable {
static func == (lhs: MessageSectionItem, rhs: MessageSectionItem) -> Bool {
return lhs.identity == rhs.identity
}
}
extension MessageSectionModel: AnimatableSectionModelType {
init(original: MessageSectionModel, items: [MessageSectionItem]) {
switch original {
case .incomingSection(let items):
self = .incomingSection(items: items)
case .outcomingSection(let items):
self = .outcomingSection(items: items)
}
}
typealias Item = MessageSectionItem
var items: [MessageSectionItem] {
switch self {
case .incomingSection(let items):
return items.map { $0 }
case .outcomingSection(let items):
return items.map { $0 }
}
}
var identity: Date {
return lastMessageDate
}
}
....
My table view is rotated because i fetch messages is reverted. I understand it`s my mistake in scan, because when i comments this code, my cells sorted in correct way, but not combined in sections.
if let lastSectionModel = sectionModels.last {
switch lastSectionModel {
case .incomingSection(var items):
if messageItem.0.isIncoming {
items.append(messageItem.0)
models[models.count-1] = .incomingSection(items: items)
} else {
models.append(.outcomingSection(items: [messageItem.0]))
}
case .outcomingSection(var items):
if messageItem.0.isIncoming {
models.append(.incomingSection(items: [messageItem.0]))
} else {
items.append(messageItem.0)
models[models.count-1] = .outcomingSection(items: items)
}
}
return models
I think you are trying to do too much at one time, and in the wrong order. Break the job up into smaller jobs that can each be easily tested/verified... Also, first group your messages by time, then put them in your sections. I ended up with this:
struct MessageItem {
let userId: String
let id: String = UUID().uuidString
let text: String
let sentDate: Date
let isIncoming: Bool
}
struct MessageGroup {
let userId: String
var text: String {
return parts.map { $0.text }.joined(separator: "\n")
}
let isIncoming: Bool
struct Part {
let id: String
let text: String
let sentDate: Date
init(_ messageSectionItem: MessageItem) {
id = messageSectionItem.id
text = messageSectionItem.text
sentDate = messageSectionItem.sentDate
}
}
var parts: [Part]
init(from item: MessageItem) {
userId = item.userId
isIncoming = item.isIncoming
parts = [Part(item)]
}
}
enum MessageSectionModel {
case incomingSection(items: [MessageGroup])
case outcomingSection(items: [MessageGroup])
}
extension ObservableType where Element == MessageItem {
func convertedToSectionModels() -> Observable<[MessageSectionModel]> {
return
scan(into: ([MessageGroup](), MessageGroup?.none), accumulator: groupByTime(messages:item:))
.map(appendingLastGroup(messages:group:))
.map(groupedByIncoming(messages:))
.map(convertedToSectionModels(messages:))
}
}
func groupByTime(messages: inout ([MessageGroup], MessageGroup?), item: MessageItem) {
if let group = messages.1 {
let lastPart = group.parts.last!
if lastPart.sentDate.timeIntervalSince(item.sentDate) > -60 && group.userId == item.userId {
messages.1!.parts.append(MessageGroup.Part(item))
}
else {
messages.0.append(group)
messages.1 = MessageGroup(from: item)
}
}
else {
messages.1 = MessageGroup(from: item)
}
}
func appendingLastGroup(messages: [MessageGroup], group: MessageGroup?) -> [MessageGroup] {
guard let group = group else { return messages }
return messages + [group]
}
func groupedByIncoming(messages: [MessageGroup]) -> [[MessageGroup]] {
return messages.reduce([[MessageGroup]]()) { result, message in
guard let last = result.last else {
return [[message]]
}
if last.last!.isIncoming == message.isIncoming {
return Array(result.dropLast()) + [last + [message]]
}
else {
return result + [[message]]
}
}
}
func convertedToSectionModels(messages: [[MessageGroup]]) -> [MessageSectionModel] {
messages.map { messages in
if messages.first!.isIncoming {
return .incomingSection(items: messages)
}
else {
return .outcomingSection(items: messages)
}
}
}

How to implement doubly linked list in swift?

How can I implement a doubly linked list in Swift with all the operations like insert and deletion?
I know how to implement singly linked list but I can't find a way to make it a doubly linked list. I am a beginner in coding.
import UIKit
struct LinkedList<Value> {
var Head : node<Value>?
var Tail : node<Value>?
var isEmpty : Bool {
return Head == nil
}
// to add at the beginning of the list
mutating func push(_ value : Value) {
Head = node(value: value, nextNode: Head)
if Tail == nil {
Tail = Head
}
}
// to add at the end of the list
mutating func append(_ value : Value) {
guard !isEmpty else {
push(value)
return
}
let newNode = node(value: value)
Tail?.nextNode = newNode
Tail = newNode
}
//to find the node at particular index
func findNode(at index: Int) -> node<Value>? {
var currentIndex = 0
var currentNode = Head
while(currentNode != nil && currentIndex < index) {
currentNode = currentNode?.nextNode
currentIndex += 1
}
return currentNode
}
// to insert at a particular location
func insert(_ value : Value, afterNode : node<Value>) {
afterNode.nextNode = node(value: value, nextNode: afterNode.nextNode)
}
mutating func pop() -> Value? {
defer {
Head = Head?.nextNode
if isEmpty {
Head = nil
}
}
return Head?.value
}
mutating func removeLast() -> Value? {
guard let head = Head else {
return nil
}
guard head.nextNode != nil else {
return pop()
}
var previous = head
var current = head
while let next = current.nextNode {
previous = current
current = next
}
previous.nextNode = nil
Tail = previous
return current.value
}
mutating func remove(after node : node<Value>?) -> Value? {
defer {
if node === Tail {
Tail = node
}
node?.nextNode = node?.nextNode?.nextNode
}
return node?.nextNode?.value
}
}
extension LinkedList : CustomStringConvertible {
var description: String {
guard let linkedListHead = Head else {
return "Empty List"
}
return String(describing: linkedListHead)
}
}
class node<Value> {
var value : Value
var nextNode : node?
init(value : Value , nextNode : node? = nil) {
self.value = value
self.nextNode = nextNode
}
}
extension node : CustomStringConvertible {
var description: String {
guard let nextValue = nextNode else { return "\(value)" }
return "\(value) -> " + String(describing: nextValue) + " "
}
}
var listOfIntegers = LinkedList<Int>()
var listOfStrings = LinkedList<String>()
listOfIntegers.push(1)
listOfIntegers.push(3)
listOfIntegers.push(4)
listOfIntegers.append(6)
let nodeInfo = listOfIntegers.findNode(at: 1)!
listOfIntegers.insert(8, afterNode: nodeInfo)
print(listOfIntegers)
listOfStrings.push("hello")
listOfStrings.push("Sardar Ji!")
print(listOfStrings)
let index = 3
let node2 = listOfIntegers.findNode(at: index - 1)
listOfIntegers.remove(after: node2)
print(listOfIntegers)
I want to implement doubly linked list the same way and the output should be like this:
node1 <-> node2 <-> node3
//here is the full implementaion of doubly-linked-list in swift. updates will be appreciated.
import Foundation
struct DoublyLinkedList<DataItem> {
fileprivate var head : Node<DataItem>?
fileprivate var tail : Node<DataItem>?
var isEmpty : Bool {
return head == nil
}
//to add at the beginning
mutating func InsertAtBeginning(_ dataItem : DataItem) {
let node = Node(dataItem: dataItem, nextNode: head, previousNode: nil)
head?.previousNode = node
head = node
if tail == nil {
tail = head
}
}
//to add at the end
mutating func insertAtEnd(_ dataItem : DataItem) {
guard !isEmpty else {
InsertAtBeginning(dataItem)
return
}
let newNode = Node(dataItem: dataItem, nextNode: nil, previousNode: tail)
tail?.nextNode = newNode
//newNode.previousNode = tail
tail = newNode
}
//to insert at particular node
func insertParticularly(_ dataItem : DataItem , afterNode : Node<DataItem>) {
let node = Node(dataItem: dataItem)
afterNode.nextNode?.previousNode = node
node.nextNode = afterNode.nextNode
afterNode.nextNode = node
node.previousNode = afterNode
}
//to find a node at particular index
func findNode(at index : Int) -> Node<DataItem>? {
var currentIndex = 0
var currentNode = head
while currentNode != nil && currentIndex < index {
currentNode = currentNode?.nextNode
currentIndex += 1
}
return currentNode
}
//MARK:- remove functionality
//remove the first element
mutating func removeFirst() -> DataItem? {
defer {
head = head?.nextNode
if isEmpty {
head = nil
}
}
return head?.dataItem
}
// remove the last element
mutating func removeLast() -> DataItem? {
guard let headValue = head else {
return nil
}
guard headValue.nextNode != nil else {
return removeFirst()
}
var previous = headValue
var current = headValue
while let next = current.nextNode {
previous = current
current = next
}
previous.nextNode = nil
tail = previous
return current.dataItem
}
// remove from a specific location
mutating func removeAt(at node : Node<DataItem>?) -> DataItem? {
defer {
if node === tail {
removeLast()
}
node?.previousNode?.nextNode = node?.nextNode
node?.nextNode?.previousNode = node?.previousNode
}
return node?.nextNode?.dataItem
}
}
extension DoublyLinkedList : CustomStringConvertible {
var description : String {
guard let doublyLinkedListHead = head else { return "UnderFlow"}
//return String(describing: doublyLinkedListHead)
return doublyLinkedListHead.linkedDescription
}
}
class Node<DataItem> {
var dataItem : DataItem
var nextNode : Node?
var previousNode : Node?
init(dataItem : DataItem , nextNode : Node? = nil , previousNode : Node? = nil) {
self.dataItem = dataItem
self.nextNode = nextNode
self.previousNode = previousNode
}
}
extension Node : CustomStringConvertible {
var description: String {
return ((previousNode == nil) ? "nil" : "\(previousNode!.dataItem)") +
" <-> \(dataItem) <-> " +
((nextNode == nil) ? "nil" : "\(nextNode!.dataItem)")
}
var linkedDescription: String {
return "\(dataItem)" + ((nextNode == nil) ? "" : " <-> \(nextNode!.linkedDescription)")
}
}
var list = DoublyLinkedList<Int>()
list.InsertAtBeginning(4)
list.insertAtEnd(5)
list.insertAtEnd(4)
list.insertAtEnd(7)
list.insertAtEnd(2)
list.insertAtEnd(0)
list.description
let node1 = list.findNode(at: 3)
node1?.previousNode
list.head
Fundamentally, your problem is that you've got head and tail pointers in LinkedList, but node only has nextNode pointer. If node is the structure representing each item in the list, and if you want to be able to traverse the list in either direction, then each item needs a link to the next item and also the previous item. That's why they call it a "doubly linked list" after all.
Add a previousNode pointer to your node structure.
Go find every spot in your code where you modify a nextNode pointer and change the code to also maintain the previousNode pointer.

Insert node in singly linked list in swift playground

Given a singly linked list, the task is to write a program to insert that element in a linked list in Swift.
import UIKit
class Node<T: Equatable>{
var value:T?
var nextNode:Node?
}
class LinkedList<T: Equatable>{
var headNode = Node<T>()
func insert(value: T){
if headNode.value == nil{
headNode.value = value
}else{
var lastNode = headNode
while lastNode.nextNode != nil {
lastNode = lastNode.nextNode!
}
let newNode: Node = Node<T>()
newNode.value = value
lastNode.nextNode = newNode
}
}
func printAllKeys() {
var currentNode: Node! = headNode
print("---------------")
while currentNode != nil && currentNode.value != nil {
print("The item is \(currentNode.value!)")
currentNode = currentNode.nextNode
}
}
}
var list = LinkedList<Int>()
list.insert(value: 5)
list.insert(value: 10)
list.printAllKeys()

Nilling out optional not working in BST implementation

I am implementing a BST and working on the remove() function, problem is when I try to nil out the node to remove i.e. current, it still exists when I print the trees structure.
class Node<T : Comparable> {
var value: T
var left: Node<T>?
var right: Node<T>?
init(_ value:T) {
self.value = value
}
}
func remove(_ value:T) {
var current: Node<T>? = root
while let root = current {
if value == root.value {
if let _ = root.left, let right = root.right {
let minValue = getMinValue(right)
root.value = minValue
remove(minValue)
} else if let left = root.left {
root.value = left.value
root.left = nil
} else if let right = root.right {
root.value = right.value
root.left = nil
} else {
//This doesn't remove the reference completely
current = nil
}
} else if value > root.value {
current = root.right
} else {
current = root.left
}
}
}
My print function still prints out the node I removed in the previous function
private func printTree(_ node:Node<T>?){
guard let root = node else {
return
}
print(root.value)
printTree(root.right)
printTree(root.left)
}
Unfortunately you just set the local variable current to nil. The parent node of current still has a reference of the node you are trying to remove.

How to check dictionary value is empty or not

i am new to swift and facing little issue and i not understanding how to check dictionary value.
func doValidate(data:Dictionary<String,AnyObject>,isEmail : String) -> Bool {
if(isEmail=="signup"){
if( data["last_name"] == nil || data["email"] == nil || data["password"] == nil || data["first_name"] == nil){
return false;
}
else{
return true;
}
}
}
Dictionary key is always constant and every time dictionary key exists but how i can check
value of data["last_name"] is empty or not?
if i used loop then its working but why single value not work?
for( myKey,myValue ) in data {
if(myValue as! String == ""){ // Work Perfect
return false;
}
}
For checking the value use objectForKey()
Here is modified code
func doValidate(data:Dictionary<String,AnyObject>,isEmail : String) -> Bool {
if(isEmail=="signup"){
if( data.objectForKey("last_name") == nil || data.objectForKey("email") == nil || data.objectForKey("password") == nil || data.objectForKey("first_name") == nil){
return false;
}
else{
return true;
}
}
}
You could consider the syntax introduced with Swift 1.2 inverting your if logic, obtaining something like this:
func doValidate(data:Dictionary<String,AnyObject>,isEmail : String) -> Bool {
if(isEmail == "signup"){
if let lastName = data["last_name"] as? String,
let email = data["email"] as? String,
let password = data["password"] as? String,
let firstName = data["first_name"] as? String
where
!lastName.isEmpty &&
!email.isEmpty &&
!password.isEmpty &&
!firstName.isEmpty {
return true
}
}
return false
}
Check length if you wanna check your string value. for example
func doValidate(data:Dictionary<String,AnyObject>,isEmail : String) -> Bool {
if(isEmail=="signup"){
if( data["last_name"]?.length == 0 || data["email"]?.length == 0 || data["password"]?.length == 0 || data["first_name"]?.length == 0){
return false;
}
else{
return true;
}
}
}