Problem-solving with ChatGPT
How I've started using ChatGPT to validate and improve my coding solutions.
Every Monday morning, a new issue of rendezvous with cassidoo drops into my inbox in which the talented Cassidy Williams shares a brief roundup of what's new and cool in the world of web development. If you don't already receive it, I suggest taking a look here. Cassidy also includes an interview question of the week which, time permitting, I like to complete.
This week's question was "Given a list of numbers, return all groups of repeating consecutive numbers." and was accompanied by a couple of examples:
> repeatedGroups([1, 2, 2, 4, 5])
[[2, 2]]
> repeatedGroups([1, 1, 0, 0, 8, 4, 4, 4, 3, 2, 1, 9, 9])
[[1, 1], [0, 0], [4, 4, 4], [9, 9]]
Initially, I thought this is nice and easy. I'll use the array reduce() and filter() methods. However, my mind went blank and, after scratching my head for a few minutes, I needed to consider a different approach. Options included:
Googling the question and finding something similar on Stack Overflow or Reddit
Changing tack and taking a different approach to finding a solution. Maybe I could refactor it to use the array methods later?
Asking ChatGPT to solve the problem
Wanting to produce my own solution I started by changing tack, using a for loop and some if statements:
function repeatedGroups(nums) {
let output = [];
let count = 0;
for (let i = 0; i < nums.length; i++) {
if (nums[i] === nums[i + 1]) {
count++;
} else {
if (count > 0) {
output.push(new Array(count + 1).fill(nums[i]));
count = 0;
}
}
}
return output;
}
It works but I wasn't 100% happy with it:
For the final iteration of
i,i+1doesn't exist.nums[i] === nums[i + 1]still resolves tofalseso it works but it feels a bit messy. It works accidentally rather than intentionally.I read in a blog post once that it's not good practice to use
else. I think this was mostly referring to longif ... else if ...chains but still, could it be improved?While it's quite easy to understand and follow the code, it feels unnecessarily verbose.
It doesn't use the array
reduce()andfilter()methods I wanted to use.
So I refactored a little:
function repeatedGroups(nums) {
let output = [];
let count = 0;
nums.forEach((num, i, fullArr) => {
if (num === fullArr[i + 1]) {
count++;
}
if (count > 0 && num !== fullArr[i + 1]) {
output.push(new Array(count + 1).fill(nums[i]));
count = 0;
}
});
return output;
}
This solution improved things a little:
It still doesn't use the array
reduce()andfilter()methods but I have replaced theforloop with aforEach()array method.I've removed the
elsestatement. Is this an improvement? Yes, I do think it is. Not only does it lose theifnested within theelse, but it makes the code more intentional. Rather than doing something that fails the firstifstatement, I'm explicitly doing these things if the two conditions are met.In terms of self-documenting code, this is better than the first attempt.
I noted that I was doing the same check, whether the current number was equal to the next number, twice. So thought about refactoring the code to do this only once:
function repeatedGroups(nums) {
let output = [];
let count = 0;
nums.forEach((num, i, fullArr) => {
switch (num === fullArr[i + 1]) {
case true:
count++;
break;
case false:
if (count > 0) {
output.push(new Array(count + 1).fill(nums[i]));
count = 0;
}
}
});
return output;
}
Again, it works, it only does the repeated number check once and is quite readable, but I don't feel it improves the previous solution. My second attempt was my preferred solution.
Now I have my solution, what does ChatGPT say?
Since ChatGPT rose to prominence I have been enjoying trying out its code-writing skills. So, once I've come up with my solution, I like to see how ChatGPT gets on with the same challenge. Here's the prompt I gave it:
In JavaScript, write a function that given a list of numbers as an array, return all groups of repeating consecutive numbers.
It's not great English but it has all the essential keywords to get a successful result. Here's what it wrote:
function getConsecutiveGroups(numbers) {
let groups = [];
let currentGroup = [];
for (let i = 0; i < numbers.length; i++) {
if (currentGroup.length === 0 || numbers[i] === currentGroup[currentGroup.length - 1]) {
currentGroup.push(numbers[i]);
} else {
if (currentGroup.length > 1) {
groups.push(currentGroup);
}
currentGroup = [numbers[i]];
}
}
if (currentGroup.length > 1) {
groups.push(currentGroup);
}
return groups;
}
It works and I was quite surprised. Not surprised that it worked, but that it came up with something similar to my original solution. I was expecting something clever, something that did the whole thing in two lines of code. However, it's using a for loop and nesting an if statement inside an else statement, as I did initially. Perhaps my solution wasn't so bad. ChatGPT has validated my initial attempt and shown me that my solution was perfectly valid.
In no time it had provided a working solution. I prefer my second solution but it shows the impressive capabilities of ChatGPT. However, I find the greatest value of ChatGPT, is when you know 90% where you want to go and can guide it towards that ultimate goal. So, I followed up with the following prompt:
Can this be simplified with ES6 array functions?
And sure enough, here's the code it came back with:
function getConsecutiveGroups(numbers) {
return numbers.reduce((acc, cur, index, arr) => {
if (index === 0 || cur !== arr[index - 1]) {
acc.push([]);
}
acc[acc.length - 1].push(cur);
return acc;
}, [])
.filter(group => group.length > 1);
}
Bingo! Once again, the code works. Now we have the array reduce() and filter() methods I wanted to use from the start. With hindsight, it's so simple I don't know why my mind went blank and I didn't come up with it myself. I like using array methods so in my opinion this is the best solution and it is nice and readable to follow what it is doing.
So my top solution for this week's challenge, courtesy of ChatGPT, is:
function repeatedGroups(nums) {
return nums
.reduce((acc, cur, ind, arr) => {
if (ind === 0 || cur !== arr[ind - 1]) acc.push([]);
acc[acc.length - 1].push(cur);
return acc;
}, [])
.filter((groups) => groups.length > 1);
}
It's intentional, readable and spans just 9 lines. Rather than wasting time struggling to find the solution I was looking for, ChatGPT got me to the solution I wanted in very little time but along the way, it also showed me that my 14-line solution was perfectly valid.
This, I think, is one of ChatGPT's strengths. ChatGPT, whilst being totally confident in everything it says, is not totally correct. It would be dangerous for someone with no coding knowledge at all to use it to develop code for them. But for someone with some knowledge, you can work with ChatGPT to improve your productivity and quickly iterate to a good solution. ChatGPT definitely provided a quicker and more tailored answer to my question than I would have gotten by reading through posts on Stack Overflow and Reddit.