Friday, 16 October 2015

Code puzzle: getting the next three elements of an array

G'day:
I've got 25min to write this, so it'll be a bit scrappy. There's an interesting question on Stack Overflow at the moment: "Get next three elements in a ColdFusion list". The basic premise is the user has a list of IDs, and - given one of the IDs in the list - wants to get back the next three IDs (or fewer if there aren't three left). Here are some test inputs and expectations:

IDsIDCountResult
[7141,6881,5821,8001,7904,6601,7961,6021,4721]71413[6881,5821,8001]
[7141,6881,5821]71413[6881,5821]
[7141]71413[]
[1111]99993[]


I didn't want to answer that using lists because they're cack, so I set about answering with arrays instead. This is still relevant as the punter starts with an array anyhow, and is turning it into a list.

I was not happy with my first answer, which was this:

function nextIds(ids, id, count){
    var thisIdIdx = ids.find(id);
    var nextIds = [];
    for (var i=thisIdIdx+1; i <= ids.len() && nextIds.len() < count; i++){
        nextIds.append(ids[i]);
    }
    return nextIds;
}

It works, but it has a loop in it and I didn't like that. It also has a shortcoming that it doesn't behave sensibly if id is not present in ids. I posted it anyhow.

I continued to mull-over the problem and then remembered CFML has an Array.slice() method these days, so knocked together a variation using that instead:

function nextIds(ids, id, count){
    var thisIdIdx = ids.find(id);
    var idsLen = ids.len();
    if (thisIdIdx == 0 || thisIdIdx == idsLen){
        return [];
    }
    return ids.slice(thisIdIdx+1, min(idsLen-thisIdIdx, count));
}

That works, but it's a lot of code for the task at hand. There must be a better way.

I wanted to use a filter() or a reduce() or something, but couldn't come up with a clean way of doing it.

How would you do it? If you'd like to submit some code, do so in a gist (not inline in the comment), and feel free to use any language you like.

Cheers!

--
Adam