Joji
Joji

Reputation: 5646

JavaScript Generator: implement a ticket queue system

I am trying to implement a ticket queue system, where by default it would have 3 different queues to holder tickets that are of severity 1, severity 2, and severity 3 respectively. And I have a method getTicketAtHighestSeverity in it that returns the oldest ticket in the highest severity queue, so it starts at the first queue and looks for the first item in the queue and moves onto the next queue if the current queue is empty and another method getTicketBySeverity to iterate through all the all queues return the ticket starting at the highest severity

Here is my implementation.

class ticketQueues {
    constructor(numOfQueues = 3) {
        this.queues = Array.from({length: numOfQueues}).fill([])
    }

    addSev1(ticket) {
        this.queues[0].push(ticket)
    }

    addSev2(ticket) {
        this.queues[1].push(ticket)
    }

    addSev3(ticket) {
        this.queues[2].push(ticket)
    }

    *getTicketBySeverity() {
        for(const queue of this.queues) {
            for(const ticket of queue) {
                yield ticket
            }
        }

        return null
    }

    getTicketAtHighestSeverity() {
        for(const queue of this.queues) {
            for(const ticket of queue) {
                return ticket
            }
        }
        
        return null
    }

}

However it seems like getTicketBySeverity is not working properly.


const queues = new ticketQueues()
queues.addSev1({timestamp: Date(), name: 't1'})
queues.addSev2({timestamp: Date(), name: 't2'})
queues.addSev3({timestamp: Date(), name: 't3'})

for(let i = 2; i >= 0; i--) {
    console.log(queues.getTicketBySeverity().next().value) // 🚨 this keeps returning the first item from the queue
}


Because it is not moving to the next ticket as it only returns the first ticket. The reason I chose Generator to implement this method is that I wanted to take advantage of the lazy evaluation model because the data set can be huge, I don't want to necessarily have to get all of the tickets all at once.

Can someone fix my implementation with getTicketBySeverity. And any suggestions about the naming here? I feel like the naming here i.e. getTicketBySeverity and getTicketAtHighestSeverity might not be the best choice. Also, feel free to comment on my usage of Generator here if you think this might not be a legit use case for that.

Upvotes: 2

Views: 1129

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 371138

One problem is

this.queues = Array.from({length: numOfQueues}).fill([])

.fill does not work well with non-primitives (usually), since each item in the new array will be a reference to the same object. You've only created a single array. The problem is the same as why the following doesn't work as one might expect:

const subarr = [];
arr.push(subarr);
arr.push(subarr);

since there's only one subarr.

Use a mapper function with Array.from to explicitly create a new array for each iteration:

this.queues = Array.from({length: numOfQueues}, () => []);

Also, to iterate over the iterator, use for..of - either that, or remove the found item from the array when it's found (otherwise, every time it's called, it'll return the same item).

You can control the number of tickets to remove at once with for..of by passing an argument to the generator and keeping track of the number of elements yielded:

class ticketQueues {
    constructor(numOfQueues = 3) {
        this.queues = Array.from({length: numOfQueues}, () => []);
    }

    addSev1(ticket) {
        this.queues[0].push(ticket)
    }

    addSev2(ticket) {
        this.queues[1].push(ticket)
    }

    addSev3(ticket) {
        this.queues[2].push(ticket)
    }
    *getTicketsBySeverity(limit) {
        let count = 0;
        for(const queue of this.queues) {
            while (queue.length) {
                yield queue.shift();
                count++;
                if (count === limit) {
                    return null;
                }
            }
        }
        return null
    }
}



const queues = new ticketQueues()
queues.addSev1({timestamp: Date(), name: 't1'})
queues.addSev1({timestamp: Date(), name: 't1-2'})
queues.addSev2({timestamp: Date(), name: 't2'})
queues.addSev3({timestamp: Date(), name: 't3'})

for (const ticket of queues.getTicketsBySeverity(3)) {
  console.log(ticket);
}
console.log(queues.queues);

Upvotes: 4

Related Questions