Harper Creek
Harper Creek

Reputation: 437

Finding nearest date within array

I'm trying to find the highest date among an array of objects with varying dates that will be attributed to each object. The code works great as long as the dates are above Jan 1st 1970, but any date before that causes error. How can I fix it with keeping the same dates obviously? I know I could use get(Time) on all the dates but is there any way around that? Thanks.

var playerData = [
    {name: "John"},
    {name: "Bill"},
    {name: "Bob"},
    {name: "Jim"},
    
];
    
var dateOne = new Date(1940,02,05);
var dateTwo = new Date(1950, 06,18);
var dateThree = new Date(1650,07,12);
var dateFour = new Date(1300, 03,25);
    
playerData[0].date = dateOne;
playerData[1].date = dateTwo;
playerData[2].date = dateThree;
playerData[3].date = dateFour;

function findHighDate() {
    var highDateSoFar = null;
    var result;
    for (var i = 0; i < playerData.length; i++) {
        if (playerData[i].date > highDateSoFar) {
            result = playerData[i];
            highDateSoFar = playerData[i].date;
        }
        else if (playerData[i].date === highDateSoFar) {	
            result = 'equal';
        
    }
    }
    return result;
}
    
var highPlayer = findHighDate();
var highPlayerName = highPlayer.name;
var highPlayerIndex = playerData.indexOf(highPlayer);
var highPlayerDate = highPlayer.date;
console.log({highPlayer},{highPlayerIndex},{highPlayerName},{highPlayerDate});

Upvotes: 0

Views: 130

Answers (6)

jo_va
jo_va

Reputation: 13964

Instead of comparing dates, you could compare the strings and use Array.sort to order them in decreasing order, then get the first item:

const playerData = [
  {name: "John", date: '1940-02-05' },
  {name: "Bill", date: '1950-06-18' },
  {name: "Bob", date: '1650-07-12' },
  {name: "Jim", date: '1300-03-25' },
];

function findHighDate() {
  return playerData.sort((a, b) => b.date.localeCompare(a.date))[0];
}
    
const highPlayer = findHighDate();
const highPlayerName = highPlayer.name;
const highPlayerIndex = playerData.indexOf(highPlayer);
const highPlayerDate = new Date(highPlayer.date);
console.log({ highPlayer, highPlayerIndex, highPlayerName, highPlayerDate });

Or you can also stick with dates and compare them using Date.getTime() for sorting your array:

const playerData = [
  {name: "John", date: new Date('1940-02-05') },
  {name: "Bill", date: new Date('1950-06-18') },
  {name: "Bob", date: new Date('1650-07-12') },
  {name: "Jim", date: new Date('1300-03-25') },
];

function findHighDate() {
  return playerData.sort((a, b) => b.date.getTime() - a.date.getTime())[0];
}
    
const highPlayer = findHighDate();
const highPlayerName = highPlayer.name;
const highPlayerIndex = playerData.indexOf(highPlayer);
const highPlayerDate = highPlayer.date;
console.log({ highPlayer, highPlayerIndex, highPlayerName, highPlayerDate });

As @Scott Sauyet pointed out in the comments below, using Array.sort may be overkill for your scenario.

You can find your highest date with a bit more code and the help of reduce:

const playerData = [
  {name: "John", date: new Date('1940-02-05') },
  {name: "Bill", date: new Date('1950-06-18') },
  {name: "Bob", date: new Date('1650-07-12') },
  {name: "Jim", date: new Date('1300-03-25') },
];

function findHighDate() {
  return playerData.reduce((highest, player) => {
    return highest.date.getTime() > player.date.getTime() ? highest : player;
  }, playerData[0]);
}
    
const highPlayer = findHighDate();
const highPlayerName = highPlayer.name;
const highPlayerIndex = playerData.indexOf(highPlayer);
const highPlayerDate = highPlayer.date;
console.log({ highPlayer, highPlayerIndex, highPlayerName, highPlayerDate });

Upvotes: 1

Scott Sauyet
Scott Sauyet

Reputation: 50787

I often find it's easier to solve a problem by moving up a level or two of abstraction. If we want to find the object that has the highest date property, I might start by writing something that finds the maximum by any given property. But even better, I could supply it with a function and find the value which maximizes that function. It turns out that this is just as easy to write as the date one, and it separates out the logic of finding the maximum from the mundane bit of choosing the date property.

So here we could write

const maximumBy = (fn) => (data) => 
  data.reduce((m, x) => fn(x) > fn(m) ? x : m, data[0])

const findHighestPlayer = maximumBy(player => player.date)

var playerData = [
    {name: "John", date: new Date(1940, 2,  5)},
    {name: "Bill", date: new Date(1950, 6, 18)},
    {name: "Bob",  date: new Date(1650, 7, 12)},
    {name: "Jim",  date: new Date(1300, 3, 25)},
];


console.log(findHighestPlayer(playerData))

Note that if your array is empty, this will return undefined, but it's hard to know what else to do. You could always add a default value parameter if that's important to fix.

Upvotes: 0

RobG
RobG

Reputation: 147343

Using > for coersion to number works most of the time, however when comparing to numbers null evaluates to 0, so negative numbers are less than null.

So just avoid that comparison either by initialising highDateSoFar to some other value (e.g. -Infinity or the first date in the array), or test for it being null, e.g.

var playerData = [
    {name: "John", date: new Date(1940, 2,  5)},
    {name: "Bill", date: new Date(1950, 6, 18)},
    {name: "Bob",  date: new Date(1650, 7, 12)},
    {name: "Jim",  date: new Date(1300, 3, 25)},
];

function findHighDate(data) {
  var highDateSoFar = null; 
  var result;
  
  for (var i=0; i < data.length; i++) {

    if (highDateSoFar === null || data[i].date > highDateSoFar) {
      result = data[i];
      highDateSoFar = data[i].date;
    }
  }
  return result ;
}

console.log( findHighDate(playerData) );

Also the expression playerData[i].date === highDateSoFar will only be true if playerData[i].date and highDateSoFar reference the same Date object, which can't be true in the logic of the function.

You can use reduce for this too:

var playerData = [
  {name: "John", date: new Date(1940, 2,  5)},
  {name: "Bill", date: new Date(1950, 6, 18)},
  {name: "Bob",  date: new Date(1650, 7, 12)},
  {name: "Jim",  date: new Date(1300, 3, 25)},
];

function getHighest(data) {
  return data.reduce((acc, high) => {
     acc = high.date > acc.date? high : acc;
     return acc;
  }, {date:-Infinity});
}

console.log(getHighest(playerData));

Upvotes: 0

dabishan
dabishan

Reputation: 691

You can do this. I have simplified the logic. You can use the sort() too, like others have suggested.

var playerData = [
    {name: "John"},
    {name: "Bill"},
    {name: "Bob"},
    {name: "Jim"},
    
];
    
var dateOne = new Date(1940,02,05);
var dateTwo = new Date(1950, 06,18);
var dateThree = new Date(1650,07,12);
var dateFour = new Date(1300, 03,25);
    
playerData[0].date = dateOne;
playerData[1].date = dateTwo;
playerData[2].date = dateThree;
playerData[3].date = dateFour;

function playerWithHighestDate() {
	// start by assuming player 0 is highest
    var winner = 0;
    
    // start at one as we dont need to compare with player 0
    for (var i = 1; i < playerData.length; i++) {
    		// compares players date
        if (playerData[i].date >= playerData[winner].date) {
            winner = i;
        }
    }
    
    // returns the winner index
    return winner;
}

// get index with highest date
var highPlayerIndex = playerWithHighestDate();
var highPlayer = playerData[highPlayerIndex];
var highPlayerName = highPlayer.name;
var highPlayerDate = highPlayer.date;
console.log({highPlayer},{highPlayerIndex},{highPlayerName},{highPlayerDate});

Upvotes: 0

Matt Way
Matt Way

Reputation: 33141

If you use getTime() on the dates, the ones prior to 1970 will simply be negative, so usual math comparisons work fine. Below I simply sort your player datas by date (max first). If you want the highest, just grab the first item in the array:

var playerData = [
  {name: "John"},
  {name: "Bill"},
  {name: "Bob"},
  {name: "Jim"},   
]
    
playerData[0].date = new Date(1940, 02, 05)
playerData[1].date = new Date(1950, 06, 18)
playerData[2].date = new Date(1650, 07, 12)
playerData[3].date = new Date(1300, 03, 25)

playerData.sort((a, b) => b.date.getTime() - a.date.getTime())

console.log(playerData)

Upvotes: 0

Badabomb
Badabomb

Reputation: 11

You can pre assign the first person's date to do the comparison like this.

var playerData = [
    {name: "John"},
    {name: "Bill"},
    {name: "Bob"},
    {name: "Jim"},

];

var dateOne = new Date(1940,02,05);
var dateTwo = new Date(1950, 06,18);
var dateThree = new Date(1650,07,12);
var dateFour = new Date(1300, 03,25);

playerData[0].date = dateOne;
playerData[1].date = dateTwo;
playerData[2].date = dateThree;
playerData[3].date = dateFour;

function findHighDate() {
    console.log(playerData);
    var highDateSoFar = playerData[0].date;
    var result = playerData[0];
    for (var i = 0; i < playerData.length; i++) {
        if (playerData[i].date > highDateSoFar) {
            result = playerData[i];
            highDateSoFar = playerData[i].date;
        }
        else if (playerData[i].date === highDateSoFar) {    

    }
    }
    return result;
}

var highPlayer = findHighDate();
var highPlayerName = highPlayer.name;
var highPlayerIndex = playerData.indexOf(highPlayer);
var highPlayerDate = highPlayer.date;
console.log({highPlayer},{highPlayerIndex},{highPlayerName},{highPlayerDate});

Upvotes: 0

Related Questions