Swift Hackerrank Dynamic Array

Posted on

Problem

I’ve solved this question. Wasn’t sure if I was suppose to use a dictionary in this case, as the question was to use a dynamic array, but I didnt know how else to do it. Was wondering if I can get feedback on my code or if there’s a better way to approach it:

enter image description here

import Foundation

// reads input for N(number of sequences) and Q(number of queries)
let input = readLine()!.componentsSeparatedByString(" ").map { Int($0)! }
let numOfSequences = input[0]
let numOfQueries = input[1]
var lastAns = 0
var seqDictionary = [Int: [Int]]()

// loop through numOfQueries
for _ in 0..<numOfQueries {
    // each query is given in format [1, x, y] or [2, x, y]
    let query = readLine()!.componentsSeparatedByString(" ").map { Int($0)! }
    // check to see if query[0] is 1 or 2
    switch query[0] {
    case 1:
        // formula for seqDictionaryIndex
        // ^ is the XOR operator
        let seqDictionaryIndex = ((query[1] ^ lastAns) % numOfSequences)
        // since we initalized an empty dictionary, we gotta set the first key to a value to start the array so we can start appending
        guard seqDictionary[seqDictionaryIndex] != nil else { seqDictionary[seqDictionaryIndex] = [query[2]] ; continue }
        seqDictionary[seqDictionaryIndex]?.append(query[2])
    case 2:
        let seqDictionaryIndex = ((query[1] ^ lastAns) % numOfSequences)
        // calculate the size of the particular sequence in seqDictionary
        let size = seqDictionary[seqDictionaryIndex]?.count
        // formula for finding index in particular sequence in seqDictionary
        let index = query[2] % size!
        // set last answer to that element at the index calculated above
        lastAns = seqDictionary[seqDictionaryIndex]![index]
        print(lastAns)
    default: break
    }
}

Solution

The task is about dynamic arrays, and using an array (instead of a
dictionary, as you did) simplifies things considerably.

If you start with an array of numOfSequences empty arrays:

var seqList = [[Int]](count: numOfSequences, repeatedValue: [])

then the 1 x y query simplifies to

let seqIndex = ((x ^ lastAns) % numOfSequences)
seqList[seqIndex].append(y)

without the need to check for an empty dictionary value.

Some more suggestions:

Reading a list of integers occurs at two places in the program, that
justifies a separate function:

func readIntegers() -> [Int] {
    return readLine()!.componentsSeparatedByString(" ").map { Int($0)! }
}

(Remark: Usually, forced unwrapping with ! should be avoided,
but here we have a programming challenge with well-defined input data.)

To increase the legibility of the code, I would assign the three
parameters of a query to variables type, x, y.
The code then becomes almost self-explaining.

The entire code then looks like this:

func readIntegers() -> [Int] {
    return readLine()!.componentsSeparatedByString(" ").map { Int($0)! }
}

// Read  N(number of sequences) and Q(number of queries):
let input = readIntegers()
let (numOfSequences, numOfQueries) = (input[0], input[1])

var lastAns = 0
// Array of `numOfSequences` empty arrays:
var seqList = [[Int]](count: numOfSequences, repeatedValue: [])

for _ in 0..<numOfQueries {
    let input = readIntegers()
    let (type, x, y) = (input[0], input[1], input[2])

    switch type {
    case 1:
        let seqIndex = ((x ^ lastAns) % numOfSequences)
        seqList[seqIndex].append(y)
    case 2:
        let seqIndex = ((x ^ lastAns) % numOfSequences)
        let index = y % seqList[seqIndex].count
        lastAns = seqList[seqIndex][index]
        print(lastAns)
    default:
        fatalError("Unexpected query")
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *