I do most of the grocery shopping for my family. Which is, of course, a privilege. But it’s a time-consuming privilege. From the moment I enter the supermarket to the moment I enter the checkout line, it’s about 30 minutes on average. Multiply that by 49 grocery trips a year, and you get 24.5 hours spent in the supermarket annually.
That’s 24 hours hours a year when I’d rather be doing basically anything else. The whole experience of grocery shopping grates on my nerves: jockeying for position with all the other shopping carts, getting the goddamn cleanup robot in my way, listening to the inane patter of the pre-recorded PA messages. It’s miserable.
All considered, I don’t mind doing it. My family needs to eat, and this is part of the cost of eating.
Why does it take me so long?
When I finally reach the end of the slog and look in my cart, I can’t help but think, there’s no way this should’ve taken me 30 minutes. There’s just not that much stuff.
So I started paying close attention to how I spend my time. Ideally, the process would look like this:
- Walk to where the milk is
- Put milk in the cart
- Walk to where the eggs are
- Put eggs in the cart
- Walk to where the bread is
- … and so on.
In reality, though, the process is much more like this:
- Look at the list and decide what to get first
- Walk in the general direction of that item
- Hopefully find the item there, and put it in the cart
- Take out my phone and check it off the list
- Look at the list again and guess which of the remaining items is closest
- Walk in the general direction of that, hoping I’ll see the right overhead sign and not miss the aisle
This process involves tremendously more context switching than the ideal. Because of deficiencies in my brain, I can’t remember more than 1 or 2 items at a time, and every context switch entails a risk of forgetting what I was in the middle of doing. Compounding with this problem is that my grocery list isn’t sorted in any particular order. I’m at the mercy of my incomplete knowledge of supermarket geography: if I miss an item because I walked past the aisle it’s in, I have to waste time walking back to that aisle.
This close examination of my time expenditure got me thinking: how much of that 30 minutes could be optimized away?
Better grocery shopping through data
It became clear that, if I wanted to spend less time in the supermarket, my best bet was to calculate the most efficient travel path through the store. Backtracking and searching were huge sources of waste. Instead, I wanted to take a single pass through the store, grabbing everything I needed as I went.
The first solution that popped into my imagination was to write a script that could take my shopping list, compare it to data about the supermarket’s layout, and produce step-by-step instructions. The instructions would look something like this:
- Starting from the store entrance,
- Go up Aisle 24. Find bread on the right side.
- Toward the back, find milk on the left side.
- Head to Aisle 14. Find yogurt against the back wall.
- Go down Aisle 12. Find coffee on the right side.
I implemented this as a simple Go program called grocery-run. This script contains a hard-coded shopping list, store layout, and arrangement of items. The simple routing algorithm traverses the aisles in order, walking down any aisle that contains an item on the shopping list, and checking that item off. It keeps track of which direction I’m walking so as to order the items appropriately and predict which side of the aisle the item will be found on. The output of
grocery-run looks like this:
This served decently for a few weeks. Each weekend before going to the supermarket, I would transfer my shopping list from the place where my family keeps it (Trello) into the code. Then I’d run the script and transfer the output to written form in a notebook. I was of course losing time with all these transfers, but my main goal at the time was just to validate the hypothesis that a path-finding algorithm like this could save me time in the long run. If that hypothesis turned out to be correct, then from there I could set my mind to optimizing away much of the overhead of using the script.
At the supermarket, I’d follow the instructions on the paper, noting the locations of any items that weren’t yet in my data set for later entry. This data recording too was a drain on my time, but – I reasoned – one that would disappear as my data set grew over multiple trips.
The initial results were encouraging! Even with the extra time spent noting item locations, I was spending the same amount of shopping time per trip. And I was also learning some important things:
- The left/right information wasn’t especially useful. Since I was spending no time mucking with my phone (as I was before, when I would refer to the list on Trello many times over the course of a trip), my eyes were free to scan the shelves on both sides of an aisle.
- The front-of-store/back-of-store information wasn’t that useful either. Because I always knew which item was next, I would see the item as I reached it. Then I could use my own judgement about whether to continue walking to the end of the aisle or turn back.
- Time spent noting item locations was indeed decreasing: from week to week, the store wasn’t getting rearranged much.
- A paper shopping list was far more efficient than using my phone. First of all, I didn’t have to go through the distracting and time-consuming exercise of taking my phone out of my pocket, unlocking it, scanning the list, and putting it back. And moreover: since the order of the paper list was aligned with my path through the supermarket, I didn’t even need to spend time or attention checking things off. Everything before the current item had already been grabbed, and everything after it remained.
The next iteration
grocery-run script served decently, but it ended up being a stepping stone to an even simpler solution. Since I didn’t need the left/right or front-of-store/back-of-store data, it turned out I could replace my whole script with a spreadsheet. When you can replace a script with a spreadsheet, it’s almost always a win.
Here’s the spreadsheet. It does basically the same thing as the
grocery-run script. There’s one sheet for the current shopping list, one for the store layout, and one for the arrangement of items within the store.
This spreadsheet makes use of a feature of Google Sheets that I hadn’t leveraged before: VLOOKUP. This function lets you construct a lookup table in one part of your spreadsheet, which can be referenced from another part. I think of this by analogy to JOINs in SQL:
SELECT shopping_list.item FROM shopping_list JOIN store_arrangement ON item JOIN store_layout ON aisle ORDER BY store_layout.visit_order;
My workflow with this spreadsheet is more or less the same as before:
- Transfer shopping list from Trello to spreadsheet
- Sort shopping list sheet by the “visit order” column (this step corresponds roughly to running the
- Transfer the resulting list to paper
The final shopping list looks like this:
The left column represents the aisle, with empty spaces indicating repetition.
Before and after
Before this intervention, my grocery shopping process was circuitous and wasteful.
Now it’s much more streamlined. Much less backtracking, no more futzing with my phone, no more checking items off the list and getting distracted in the meantime.
All told, this saves me about 15 minutes a week of shopping time. Over the course of the year, that’s
(15m) * (49 weeks a year, adjusting for vacation) = 12.25h
I like to think of this as about 1 book: due to this optimization, I get to read about 1 extra book a year, or do something else of equivalent value. Plus, I get to spend 12 hours less each year listening to that insipid Stop & Shop PA loop. I’ll take it!