Fattaneh Talebi
Fattaneh Talebi

Reputation: 767

Data structure for consecutive array in swift

I have two arrays, which are used consecutively.

var pinnedMessage: [Message]
var normalMessage: [Message]

First

I add the pinned messages to the first array and normal ones to the second. bu I always use both arrays Consecutive. so when I use them I make a new array, first append pinned messages then normal messages.

var newArray: [Message] = []
newArray.append(pinnedMessage)
newArray.append(normalMessage)

Second

Another way is that I put both messages in one array and then sort them based on if their isPinned property.

GlobalArray.sort { $0.isPinned && !$1.isPinned }

I also should know where is the index of first normal message. so I have a variable for that too.

I don't think if these ideas are ok. Should I use linked list or other data structure?

Upvotes: 0

Views: 95

Answers (3)

Suhit Patil
Suhit Patil

Reputation: 12023

You can create a single array with both pinned and normal messages added consecutively and use Swift 4.2 firstIndex(where:) method on Collections to get the first index of normal message

struct Message {
    let isPinned: Bool
}

let pinned = [Message(isPinned: true), Message(isPinned: true), Message(isPinned: true)]
let normal = [Message(isPinned: false), Message(isPinned: false), Message(isPinned: false)]
let sortedArray = pinned + normal

if let firstIndex = sortedArray.firstIndex(where: { $0.isPinned == false }) {
    print(firstIndex)
}

if you're doing it in UIViewController then can use didSet observer on the sortedArray to set the firstIndex of normal message

class ViewController: UIViewController {

    var normalPinFirstIndex: Int?

    var sortedArray: [Message] = [] {
       didSet {
            if !sortedArray.isEmpty {
                normalPinFirstIndex = sortedArray.firstIndex(where: { $0.isPinned == false })
            }
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        let pinned = [Message(isPinned: true), Message(isPinned: true), Message(isPinned: true)]
        let normal = [Message(isPinned: false), Message(isPinned: false), Message(isPinned: false)]
        sortedArray =  pinned + normal
        if let firstIndex = normalPinFirstIndex {
            print(firstIndex)
        }
    }
}

Upvotes: 0

Andreas condemns Israel
Andreas condemns Israel

Reputation: 2338

Rather than using any of the alternatives you've listed, you could instead alter the way that you access your arrays. You can use a helper function, taking a closure as an argument, to process each element in the arrays:

struct Message {
    let text: String
}

let pinnedMessages: [Message] = [Message(text: "I'm pinned"), Message(text: "I'm also pinned")]
let normalMessages: [Message] = [Message(text: "I'm normal"), Message(text: "I'm also normal")]
@inline(__always)
func foreachMessage(function: (Message) throws -> ()) rethrows {
    try pinnedMessages.forEach(function)
    try normalMessages.forEach(function)
}

If you also need to know the type of the message, you should either process the arrays individually, without a helper function, or let your closure take another argument:

enum MessageType {
    case pinned
    case normal
}


@inline(__always)
func foreachMessage(function: (Message, MessageType) throws -> ()) rethrows {
    try pinnedMessages.forEach { try function($0, .pinned) }
    try normalMessages.forEach { try function($0, .normal) }
}
foreachMessage { message in
    print(message)
}

foreachMessage { message, type in
    print(message, type)
}

Using this kind of method, frees you from the disadvantage of concatenating the two arrays: memory and performance overhead.

If you're displaying these messages as if they're in one array, the index of the first normal message, will simply be after the index of the last message in the pinnedMessages array. pinnedMessages.count will be equal to that array's last index + 1, equalling the first index of the normal messages.

Upvotes: 1

Mohmmad S
Mohmmad S

Reputation: 5088

I have created the same situation you are in check out this code.

struct Message {
    var isPinned: Bool
}

var pinnedArray: [Message] = [Message(isPinned: true),Message(isPinned: true),Message(isPinned: true),Message(isPinned: true)]
var notPinnedArray: [Message] = [Message(isPinned: false),Message(isPinned: false),Message(isPinned: false),Message(isPinned: false)]

var sortedArray: [Message]  = pinnedArray + notPinnedArray // this will put pinned Array first then add the normal one after it so it would be [true, true, ture, true, false, false, false, false ]
var indexForFirstNormalMessage = pinnedArray.count //index for the first normal message is the count of the pinnedArray because array indexing starts at 0 and counting starts at 1 so  using the count of the pinned array as index in the sorted one, would get you the first normal message index.
print(indexForFirstNormalMessage) // 4

sortedArray.forEach {message in
    print(message)
}
/* Message(isPinned: true)
 Message(isPinned: true)
 Message(isPinned: true)
 Message(isPinned: true)
 Message(isPinned: false)
 Message(isPinned: false)
 Message(isPinned: false)
 Message(isPinned: false)*/

Upvotes: 0

Related Questions