2

I need to get all unique days of multiple date values in the format DD.MM.. In this example data, there are two values for the 24th of december:

const data = [
    { date: ISODate("2019-12-24T03:24:00Z") },
    { date: ISODate("2019-12-24T04:56:00Z") },
    { date: ISODate("2019-12-25T02:34:00Z") },
    { date: ISODate("2019-12-26T01:23:00Z") }
]

So the result should be

const result = [
    '24.12.',
    '25.12.',
    '26.12.'
]

So first of all I'll map my data and split the values only for the dates:

const dates = data.map(d => d.date.toString().split('T')[0])

But how do I get the unique values and change the output format?


Update

I came up with this, but it looks very complicated...

data.map(d => {
  const dateSplit = d.date.toString().split('T')[0].split('-')
  return dateSplit[2] + '.' + dateSplit[1] + '.'
})
.filter((value, index, self) {
  return self.indexOf(value) === index
})
user3142695
  • 15,844
  • 47
  • 176
  • 332

5 Answers5

5

It seems that ISODate returns a standard JS Date object. You can use Date.getDate() to get the day, and Date.getMonth() to get the month (0 based, so we need to add 1):

const data = [
  { date: new Date('2019-12-24T03:24:00Z') },
  { date: new Date('2019-12-24T04:56:00Z') },
  { date: new Date('2019-12-25T02:34:00Z') },
  { date: new Date('2019-12-26T01:23:00Z') }
]

const result = [...new Set(data.map(({ date: d }) => 
  `${d.getDate()}.${d.getMonth() + 1}.`
))]

console.log(result)

Previous answer:

Use a regular expression to match the month and the day, and assign them to consts using destructuring. Assemble the string using template literal. Remove duplicates by assigning the values to a Set, and then spreading back to an array.

Note: Since I don't have access to the ISODate, I've removed it. I left .toString() although it's not needed in this example, but will be needed when used with ISODate.

const data = [
  { date: '2019-12-24T03:24:00Z' },
  { date: '2019-12-24T04:56:00Z' },
  { date: '2019-12-25T02:34:00Z' },
  { date: '2019-12-26T01:23:00Z' }
]

const pattern = /-([0-9]{2})-([0-9]{2})T/

const result = [...new Set(data.map(d => {
  const [, mon, day] = d.date.toString().match(pattern)
  
  return `${day}.${mon}.`;
}))]

console.log(result)
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
0

Use .filter() to filter through only values that are the first of their value.

//temporary function
const ISODate = (d) => d;

const data = [{
    date: ISODate("2019-12-24T03:24:00Z")
  },
  {
    date: ISODate("2019-12-24T04:56:00Z")
  },
  {
    date: ISODate("2019-12-25T02:34:00Z")
  },
  {
    date: ISODate("2019-12-26T01:23:00Z")
  }
]

const dates = data.map(d => d.date.toString().split('T')[0].split("-").slice(1, 3).reverse().join(".") + ".")

console.log(dates.filter((v, i, a) => a.indexOf(v) === i));
Yousername
  • 1,012
  • 5
  • 15
0

You can do this pretty easily by using Array.reduce. Note that I converted ISODate to be Date since I don't have that class, but it should be the same concept.

const data = [
    { date: new Date("2019-12-24T03:24:00Z") },
    { date: new Date("2019-12-24T04:56:00Z") },
    { date: new Date("2019-12-25T02:34:00Z") },
    { date: new Date("2019-12-26T01:23:00Z") }
];
const result = data.reduce( (acc, curr) => {
  if (acc.length > 0) {
    const hasDate = acc.find(d => d.date.getMonth() === curr.date.getMonth() && d.date.getDate() === curr.date.getDate());
    if (!hasDate) { acc.push(curr); }
  } else {
    acc.push(curr);
  }
  return acc;
}, []);

console.log(result);
mwilson
  • 12,295
  • 7
  • 55
  • 95
-1

I would use the uniq function in the Underscore.js library:

const data = [
    { date: ISODate("2019-12-24T03:24:00Z") },
    { date: ISODate("2019-12-24T04:56:00Z") },
    { date: ISODate("2019-12-25T02:34:00Z") },
    { date: ISODate("2019-12-26T01:23:00Z") }
];

let dates = _.uniq(data.map(d => d.date.toString().split('T')[0]));
Ken Keenan
  • 9,818
  • 5
  • 32
  • 49
  • But how do I get the expected result (changed format)? – user3142695 Dec 27 '19 at 00:15
  • 3
    I disagree. Importing an entire library just to get a unique array is too much. You can write a function in a couple lines of code to do this. Why would you import thousands of lines of code when you're only going to use a single function? `Array.reduce` is your friend here. – mwilson Dec 27 '19 at 00:16
  • @mwilson: Yes, importing Underscore just for this one function would be overkill, I agree. But it is a useful library to have around if you find yourself doing a lot of this kind of data manipulation. There are also alternatives such as [lodash](https://lodash.com/docs#uniq) which have most of the functionality of Underscore but aren't as heavy. – Ken Keenan Dec 27 '19 at 12:12
-1

A nice considerable way is:

const array = [1, 2, 6, 5,5, 5, 3, 7, 8];

const uniqueKeys = array.reduce((hashMap, value) => {
  if (!hashMap[value]) {
    hashMap[value] = true;
  }
  return hashMap;
}, {});

const uniqueValues = Object.keys(uniqueKeys);

console.log(uniqueValues);

It is nice because it iterates the array once, instead of x * x (a.k.a log(n) instead of log(n^2) as with .filter() example

const array = [1, 2, 6, 5,5, 5, 3, 7, 8];

const uniqueKeys = array.reduce((hashMap, value) => {
  if (!hashMap[value]) {
    hashMap[value] = true;
  }
  return hashMap;
}, {});

const uniqueValues = Object.keys(uniqueKeys);

console.log(uniqueValues);
shuk
  • 1,745
  • 1
  • 14
  • 25