Find the fastest run of each year from a list of running results
First solution using .forEach, for...in and .sort

Here what I did to achieve this:


First sort your array of objects, i.e convert:

data = [ {...}, {...}, {...}, {...}, {...}, {...} ]


into an object sorted by year:

sortedY = { 2017: [{...}, {...}, {...}], 2018: [{...}, {...}, {...}] }


You can achieve such result by using a forEach loop:

const sortedY = {};
data.forEach(e =&gt; {
    const year = e.date.split('-')[0];
    sortedY[year] = sortedY[year] || [];
    sortedY[year].push(e);
});

Then we will need to sort each object [{...}, {...}, {...}] per year by duration. sorted is not an array. We can't use map unfortunately: use a for...in loop instead. However to sort each key/value (&lt;=> year/array of results for this year) we can use one of Array's methods: sort, the sorting criteria is the following:

(a,b) =&gt; a.duration &gt; b.duration


Where a and b are two different races from the same year.

So with:

sortedY[year].sort((a,b) =&gt; a.duration &gt; b.duration)


You get an array of sorted races for the year year.

The last thing to do is saving the first of the sorted array (the first is the one with the shortest duration, so select it with [0] and add it to result:

result[year] = sortedY[year].sort((a,b) =&gt; a.duration &gt; b.duration)[0]





The final code is:



const sortedY = {};
data.forEach(e =&gt; {
    const year = e.date.split('-')[0];
    sortedY[year] = sortedY[year] || [];
    sortedY[year].push(e);
});

const result = {};
for(year in sortedY) {
   result[year] = sortedY[year].sort((a,b) =&gt; a.duration &gt; b.duration)[0];
}

console.log(result);
&lt;script&gt;
const data = [ { id: 1, date: '2017-01-01 00:00:00', duration: 195 }, { id: 2, date: '2017-01-10 00:00:00', duration: 270 }, { id: 3, date: '2017-03-12 00:00:00', duration: 220 }, { id: 4, date: '2018-01-10 00:00:00', duration: 218 }, { id: 5, date: '2018-02-23 00:00:00', duration: 220 }, { id: 6, date: '2018-05-18 00:00:00', duration: 215 } ]
&lt;/script&gt;






Second solution using only .forEach

I realised there was a quicker way of doing this: we don't need to loop over the array data twice! One loop will suffice. Indeed, we'll fill result as we navigate through data only replacing a yearly race if a race is shorter in duration.

So a race will be added to result[year] only if:

!result[year] || (result[year] &amp;&amp; e.duration &lt; result[year].duration)


is true, i.e. if either:


there is no race registered for the year year
there is one but its duration is longer than the one that we're checking


So the code is shorter, simpler and I bet it will be quicker: its complexity is \$O(n)\$. The previous code was cool but not so much efficient. I was looping twice the data: first time for the sorting, second on the sorted array. Not even mentioning that I was using sort...



let result = {};
data.forEach(e =&gt; {
  const year = e.date.split('-')[0];
  if( !result[year] || (result[year] &amp;&amp; e.duration &lt; result[year].duration) ) {
    result[year] = e;
  }
})

console.log(result);
&lt;script&gt;
const data = [ { id: 1, date: '2017-01-01 00:00:00', duration: 195 }, { id: 2, date: '2017-01-10 00:00:00', duration: 270 }, { id: 3, date: '2017-03-12 00:00:00', duration: 220 }, { id: 4, date: '2018-01-10 00:00:00', duration: 218 }, { id: 5, date: '2018-02-23 00:00:00', duration: 220 }, { id: 6, date: '2018-05-18 00:00:00', duration: 215 } ]
&lt;/script&gt;