How to get unique date values from object array - javascript

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
})

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)

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));

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);

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]));

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);

Related

Sort array with timestamps and merge similar dates

I am trying to take this array :
[
{
"date": a timestamp: June 20, 2020 at 7:32:42 PM UTC
"value": 3
..
}
..
]
and accomplish 3 things effeciently
Convert the timestamp to normal date and replace with the timestamp
Merge dates of the same day. ( so i add their values and set under a single day.
Sort the array when recent are first.
I have started with something like this :
array.sort(function(a,b){ return new Date(b.date) - new Date(a.date);
var salesDates = sales.map(function(element){element.date = new Date(element.date); return element }); });
Which will only sort, but i need to replace timestamp/date, sort and merge same dates elegantly and effeciently
Is it possible with only sort function ?
Here. First i group it with .reduce(). Then i sort it .sort(). After that i change the timestamp to a date format.
let arr = [
{
"date": 1594023899426,
"value": 3
},
{
"date": 1592423499234,
"value": 2
},
{
"date": 1594023899426,
"value": 1
}
];
let result = arr
.reduce((a, v) => {
let index = a.findIndex(el => el.date === v.date);
if (index !== -1) {
a[index].value += v.value;
return a;
}
a.push({
date: v.date,
value: v.value
});
return a;
}, [])
.sort((a, b) => b.date - a.date)
.map(el => {
el.date = new Date(el.date);
return el;
});
console.log(result);
Here's another approach to it:
let sortingReducer = (accumulator, obj) => {
// This is the merging logic
let existingObj = accumulator.find(
(compareObj) => {
return obj.date?.getDate() === compareObj.date?.getDate()
}
);
if (existingObj) {
existingObj.value += obj.value;
return accumulator;
}
// This is the sorting logic
const nextIndex = accumulator.findIndex(
(compareObj) => obj.date?.getTime() < compareObj.date?.getTime()
);
const index = nextIndex > -1 ? nextIndex : accumulator.length;
accumulator.splice(index, 0, obj);
return accumulator;
};
const input = [
{
date: new Date(),
value: 2,
},
{
date: new Date(new Date().setDate(1)),
value: 4,
},
{
date: new Date(new Date().setDate(1)),
value: 1,
},
{
date: new Date(new Date().setDate(2)),
value: 7,
},
];
const output = input.reduce(sortingReducer, []);
I've take some help from this answer: https://stackoverflow.com/a/50246275/1912288
I like the approach in the above answer, this is just a different approach to it.

How to check if key of object in array has specific value in javascript

Is it possible to check if an object in an array has a specific Date value in the following data format?
I have an array like this for example
[
{
date: '2020-05-03',
items: [{}...]
},
...
]
-> In the above array, I want to check if any object in the array has '2020-05-03' as the date value.
And I want to find out if an object with Date is ??
I tried the following, but this only confirms that it has a 'date' as the key, and I couldn't compare values.
const existsDate = _.find(prev, 'date');
I also want to push an item to the items of the object containing that date if a date already exists.
If not, i need to create a new date object.
you caan use filter or find function
let arr = [
{data:'2020-05-23'},
{data:'2020-06-23'},
{data:'2020-07-23'}
]
let find = arr.find( (val) => val.data == '2020-06-23')
console.log(find)
You can make use of Array.prototype.find and do a string comparison
var arr = [
{
date: '2020-05-03',
items: [{}...]
},
]
const obj = arr.find(item => item.data === '2020-05-03');
EDIT: Since you want to update the existing array, you would need to make use of slice with findIndex to update array
var arr = [
{
date: '2020-05-03',
items: [{}...]
},
]
const newItem = {};
const index= arr.findIndex(item => item.data === '2020-05-03');
if(index > -1) {
arr = [...arr.slice(0, index), {...arr[index], items: arr[index].items.concat(newItems), ...arr.slice(index + 1)}
} else {
arr.push({data: new Date(), items: [newItem]})
}
You can use, Array find(), some() to get/check the required conditions, for example:
const arr = [
{
date: '2020-05-03',
items: [{}]
},
{
date: '2020-05-02',
items: [{}]
}
]
function checkAndAdd(date) {
const res = arr.find(ob => ob.date === date);
// console.log(res);
// based on the added comments.
// if date is found, push something to the items, list:
if (res) {
res.items.push('Hello');
} else {
arr.push({
date,
items: [{}]
})
}
console.log('finalArray', arr);
}
checkAndAdd('2020-05-03');
checkAndAdd('2020-05-06');
I'm not sure what exactly you are looking to do but his code iterates through the array of objects and checks against the date variable. It outputs the index (i).
let date = "2020-05-03"
const array = [
{ date: "2020-05-01" },
{ date: "2020-05-02" },
{ date: "2020-05-03", },
]
for(let i = 0 ; i < array.length ; i ++) {
if(array[i].date === date) {
console.log(i); }
else {
console.log("Date not in array");
}
}

Eliminate array entries based on date

I have an array of data similar to this:
var items = [
{ id: 84, "completedDate":"2019-01-26T17:45:07.895Z" },
{ id: 92, "completedDate":"2019-02-26T17:45:07.895Z" },
{ id: 123, "completedDate":"2019-03-26T17:45:07.895Z" },
{ id: 2353, "completedDate":"2019-04-26T17:45:07.895Z" }
];
I would like to return an array with only objects less than 30 days old.
I have tried to filter
var filtered = items.filter(function(item) {
return moment(item.completedDate) > moment.subtract(30, 'days');
});
Is this what I need to do, or is there a better way to do this?
You don't need moment to compare dates:
const compareDate = new Date();
compareDate.setDate(compareDate.getDate() - 30);
const filtered = items.filter(item => new Date(item.completedDate) > compareDate);
Here's a similar way to do this without moment. here we just get the current day, reset the time back to the start of the day (you may or may not need this for your use case) and then we just use plain JS date objects to compare
var items = [
{ id: 84, "completedDate":"2019-01-26T17:45:07.895Z" },
{ id: 92, "completedDate":"2019-02-26T17:45:07.895Z" },
{ id: 123, "completedDate":"2019-03-26T17:45:07.895Z" },
{ id: 2353, "completedDate":"2019-04-26T17:45:07.895Z" }
];
var thirtyDaysAgo = new Date();
thirtyDaysAgo.setHours(0, 0, 0, 0);
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
var filtered = items.filter(function(item) {
var d = new Date(item.completedDate).getTime();
return d > thirtyDaysAgo;
});
console.log(filtered);
Or, an even smaller filter function (if you don't need IE 11 support) would be:
var filtered = items.filter((item) => new Date(item.completedDate).getTime() > thirtyDaysAgo);
try
items.filter( x=> x.completedDate > today.toISOString() );
var items = [
{ id: 84, "completedDate":"2019-01-26T17:45:07.895Z" },
{ id: 92, "completedDate":"2019-02-26T17:45:07.895Z" },
{ id: 123, "completedDate":"2019-03-26T17:45:07.895Z" },
{ id: 2353, "completedDate":"2019-04-26T17:45:07.895Z" }
];
var today = new Date("2019-04-20T17:45:07.895Z") // or: new Date()
today = new Date(+today - 30 *86400000)
let r= items.filter( x=> x.completedDate > today.toISOString() );
console.log(r);

Compare array items

I got array (someObjects) of some objects (someObject) with two properties - number and date. I want to compare all objects in array with each others. If in array exist object with smaller number and latest date than other objects - I need to return "not ok".
How can I do that in JavaScript?
const filterFunc = (a, _, array) => {
return (array.some(el => el.number > a.number) && array.some(el => el.date < a.date));
};
const isNotOk = array => {
if (array.some(filterFunc)) console.log("not ok");
};
const someObjects = [{ number: 42, date: new Date(999999999999) }, { number: 7, date: new Date(555555555555) }];
const someObjects2 = [{ number: 1, date: new Date(999999999999) }, { number: 7, date: new Date(555555555555) }];
isNotOk(someObjects); // prints "not Ok"
isNotOk(someObjects2); // does nothing

sort deep object in javascript

What is the best way to sort this:
{
abc: {
string: 'lorem',
date: 2
},
enc: {
string: 'ipsum',
date: 1
}
}
into this:
[{
id: 'enc',
string: 'ipsum',
date: 1
},
{
id: 'abc',
string: 'lorem',
date: 2
}]
I need an array sorted by the date (Number) with a flat object.
First, you need to convert the original object into an array in the format you want:
var arr = [];
for (var key in obj)
if (obj.hasOwnProperty(key)) {
var o = obj[key];
arr.push({ id: key, string: o.string, date: o.date });
}
Then, you can use the array sort method with a custom comparator for sorting by the date field:
arr.sort(function(obj1, obj2) {
return obj1.date - obj2.date;
});
This will do the trick.
var stuff = {
abc: {
string: 'lorem',
date: 2
},
enc: {
string: 'ipsum',
date: 1
}
};
// Put it into an array
var list = [];
for(var i in stuff) {
if (stuff.hasOwnProperty(i)) {
list.push(stuff[i]);
}
}
// sort the array
list.sort(function(a, b) {
return a.date - b.date;
});
See also:
https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference:Global_Objects:Array:sort
I would do it in two steps: First, convert the object to an array:
var array = [],
o;
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
o = obj[key];
o.id = key;
array.push(o);
}
}
Then, sort it like this:
array.sort(function (a, b) {
a.date - b.date;
});
Here's my quick one-liner for this:
let new = Object.entries(obj).map((n) => ({ id: n[0], ...n[1] })).sort(({ date: a }, { date: b }) => a - b)
Let's break it down:
let new = Object.entries(obj); // convert object to [ key, value ] array
new = new.map((n) => ({ id: n[0], ...n[1] }) ); // map array to [ { id: key, ...value } ]
new = new.sort(({ date: a }, { date: b }) => a - b); // sort by date

Categories