Change index in array.map - javascript

I have a variable of the form:
var data=[
{
start:22,
end: 8
},
{
start:60,
end: 43
},
{
start: 35,
end: 55
},
{
start:25,
end:40
}
];
I want to map it to look like this
var newData = { 22:8, 60:43, 35:55, 25:40};
Is this possible? I mainly just want to use the start numbers as a key to access the end numbers without using search. I have tried to do this:
var mapData = data.map(function(data){
var x = {};
x[data.start]=data.end;
return x;
});
but it gives:
0
:
{22: 8}
1
:
{60: 43}
2
:
{35: 55}
3
:
{25: 40}
which means i have to use 0, 1,2, 3 as indices.

Only Array#map does not work in this case, because without post processing, you get a single array with objects. You need to combine all objects into a single object.
With Object.assign and spread syntax ..., you get a single array with all properties from the objects in the array.
var data = [{ start: 22, end: 8 }, { start: 60, end: 43 }, { start: 35, end: 55 }, { start: 25, end: 40 }],
result = Object.assign(...data.map(({ start, end }) => ({ [start]: end })));
console.log(result);

You can use array.reduce:
var data=[
{
start:22,
end: 8
},
{
start:60,
end: 43
},
{
start: 35,
end: 55
},
{
start:25,
end:40
}
];
var res = data.reduce((m, o) => {
m[o.start] = o.end;
return m;
}, {});
console.log(res);

Related

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

how to assign object in object

how to assign the object in object and filter the value which pass and fail;
the input is:
[
{
name: 'John',
score: 90,
time: 'evening'
},
{
name: 'Doni',
score: 68,
time: 'morning'
},
{
name: 'Jiu',
score: 50,
time: 'evening'
},
{
name: 'Shin',
score: 92,
time: 'morning'
},
];
and i want the output like this :
{
"evening": {
"pass": [
{
"name": "John",
"score": 90
}
],
"fail": [
{
"name": "jiu",
"score": 50
}
]
},
"morning": {
"pass": [
{
"name": "Shin",
"score": 92
}
],
"fail": [
{
"name": "Doni",
"score": 68
}
]
}
}
do we need to use Object.assign for this ? and how many loop we use for this ??
i do love to know how to add another string in the object beside that ouput,
thanks
There's a lot of ways to do this. The simplest is probably to make a base object that represent your empty results. Then loop over the students and fill the arrays:
let students = [{name: 'John',score: 90,time: 'evening'},{name: 'Doni',score: 68,time: 'morning'},{name: 'Jiu',score: 50,time: 'evening'},{name: 'Shin',score: 92,time: 'morning'},];
// Empty case
let base = {
"evening": {"pass": [], "fail": []},
"morning": {"pass": [], "fail": []}
}
const PASSING = 70
students.forEach(({name, score, time}) => {
let key = score >= PASSING ? 'pass' : 'fail'
base[time][key].push({name, score})
})
console.log(base)
This makes is easy to have empty arrays, which is probably what you want if there are no students in a particular category.
EDIT based on comment:
To support arbitrary times, you can just create the times on the object as you find them. reduce() is good for this, but you could also use a regular loop. For example with an added afternoon time:
let students = [{name: 'Mark',score: 95,time: 'afternoon'}, {name: 'John',score: 90,time: 'evening'},{name: 'Doni',score: 68,time: 'morning'},{name: 'Jiu',score: 50,time: 'evening'},{name: 'Shin',score: 92,time: 'morning'},];
const PASSING = 70
let result = students.reduce((obj, {name, score, time}) => {
if (!obj[time]) obj[time] = {'pass': [], 'fail': [] }
let key = score >= PASSING ? 'pass' : 'fail'
obj[time][key].push({name, score})
return obj
}, {})
console.log(result)
You can do something like this:
const data = [{ name: 'John', score: 90, time: 'evening' }, { name: 'Doni', score: 68, time: 'morning' }, { name: 'Jiu', score: 50, time: 'evening' }, { name: 'Shin', score: 92, time: 'morning' }, ];
const grp = (d, p) => d.reduce((r,c) => (r[c[p]] = [...r[c[p]] || [], c], r), {})
const grpV = (d, rng) => d.reduce((r,{name, score}) => {
let key = score > rng ? 'pass' : 'fail'
r[key] = [...r[key] || [], {name, score}]
return r
}, {})
const r = Object.entries(grp(data, 'time')).map(([k,v]) => ({[k]: grpV(v, 75)}))
console.log(r)
The idea is the group 2 times one on the time and 2nd on the score.
grp: function to group by a property (in this case 'time') which returns an object with 2 properties: evening and morning each of which is an array containing the classes.
grpV: function to group by value (in this case 75) which returns an object with 2 properties: pass and fail each of which is an array containing the classes.
On the end once we have those tools we are saying ... give me the entries of the grouped by time object and for each of the groups ... group by score.
Here how something like this could look like if we ware using lodash:
const data = [{ name: 'John', score: 90, time: 'evening' }, { name: 'Doni', score: 68, time: 'morning' }, { name: 'Jiu', score: 50, time: 'evening' }, { name: 'Shin', score: 92, time: 'morning' }, ];
const partition = (x, p) => _(x)
.partition(y => y.score > p)
.map((x,i) => ({ [i==0 ? 'pass': 'fail']: _.omit(x[0], 'time')}))
.value()
const r = _(data)
.groupBy('time')
.mapValues(x => partition(x, 75))
.value()
console.log(r)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Adding it as an example since it does help with readability of what the ES6 example is doing to some extend.
I'm sure there are more elegant ways to do this. But this one is probably one of the simplest beginner-friendly ways you can go about this.
I loop through the input array, check the existence of the .time values as keys on the output object and create the pass and fail keys. Then evaluate the .score against the passingScore and push the necessary data to it.
Should be pretty easy to understand once you see and try the code below:
const data = [
{name: 'John',score: 90, time: 'evening'},
{name: 'Doni',score: 68, time: 'morning'},
{name: 'Jiu',score: 50, time: 'evening'},
{name: 'Shin',score: 92, time: 'morning'},
{name: 'Fubar',score: 75, time: 'noon'},
];
function formatData(data){
const passingScore = 75;
const output = {};
data.forEach(function(item){
if(!output[item.time]) output[item.time] = {pass: [], fail: []};
const stud = { name: item.name, score: item.score };
if(item.score >= passingScore) output[item.time]['pass'].push(stud)
else output[item.time]['fail'].push(stud)
});
return output;
}
console.log(formatData(data));

Merge two array of timelines into one

Hey guys I am currently stuck on a question.
I have to merge to timelines. Each timeline is given as an array of objects.
Currently my thought process was to concat then sort both inputs. After that, compare start and end times. Any help ?
The original question:
Write a function to merge two array timelines into one. If an objects value is different, your new value should be false.
I CREATED THIS TO VISUALLY UNDERSTAND THE QUESTION BETTER:
Timeline1:
// null 45 89 null
// <-----------||---------------------||----------------->
// true false true
Timeline2:
// null 67 null
// <-----------------------||---------------------------->
// true false
MergedTimeline:
// null 45 67 89 null
// <-----------||----------||---------||----------------->
// true false false false
Example inputs:
let timeline1 = [
{ start: null, end: 45, value: true },
{ start: 45, end: 89, value: false },
{ start: 89, end: null, value: false }
]
let timeline2 = [
{ start: null, end: 67, value: true },
{ start: 67, end: null, value: false }
]
//expected output
return [
{ start: null, end: 45, value: true },
{ start: 45, end: 67, value: false },
{ start: 67, end: 89, value: false },
{ start: 89, end: null, value: false }
]
Here is my current attempt:
const mergeTimeline = (arr1,arr2) =>{
let combine = arr1.concat(arr2)
let sortedTimeline= combine.sort((a,b)=>{
return a.start - b.start
})
const mergedTimeline = [sortedTimeline[0]];
for (let i = 1; i < sortedTimeline.length; i++) {
const currentTimeLine = sortedTimeline[I];
const lastMergedTime = mergedTimeline[mergedTimeline.length - 1]
if (lastMergedTime.value !== currentTimeLine.value) {
currentTimeLine.value = false
lastMergedTime.end = Math.max(lastMergedTime.end,currentTimeLine.start)
mergedTimeline.push(currentTimeLine)
} else{
mergedTimeline.push(currentTimeLine)
}
}
return mergedTimeline
}
mergeTimeline(timeline1,timeline2)

How do i loop through object and remove properties which are not equal to something

Below code removes hours and days properties.What I am trying to do is remove properties which are not equal to hours and days.How do I iterate properties and check if it's not equal then remove?
Object.keys(allcoursetimeobject).forEach(function(key) {
//this removes hours and days.I want to remove properties which are not equal to hours and days.
delete allcoursetimeobject[key].hours;
delete allcoursetimeobject[key].days;
});
Just repeat the loop
allcoursetimeobject = {
test1 : {
hours : 3,
days : 4,
something : 3,
},
test2 : {
hours : 3,
days : 4,
somethingElse : 5,
}
}
Object.keys(allcoursetimeobject).forEach(function(key) {
Object.keys(allcoursetimeobject[key]).forEach(function(secondKey){
if(allcoursetimeobject[key][secondKey] !== allcoursetimeobject[key].hours && allcoursetimeobject[key][secondKey] !== allcoursetimeobject[key].days){
delete allcoursetimeobject[key][secondKey];
}
});
});
console.log(allcoursetimeobject);
demo
You can use Object.keys() to iterate through keys of an object and then using array#includes you can check if a key exists in a given array. If found, delete it using delete.
const oldObject = { key1: { hours: 3, days: 4, prop1: 3, }, key2: { hours: 3, days: 4, prop2: 5, } };
Object.keys(oldObject).forEach(k => {
Object.keys(oldObject[k]).forEach(key => {
if(['hours','days'].includes(key)){
delete oldObject[k][key];
}
});
});
console.log(oldObject);
Assumptions:
You want to delete properties from objects within the allcoursetimeobject, based on the code snippet provided by you.
Then answer is:
var allcoursetimeobject = {
a: {
hours: 10,
days: 20,
test: "Delete This"
},
b: {
hours: 5,
days: 15,
test: "Delete This"
}
};
Object.keys(allcoursetimeobject).forEach(function(key) {
Object.keys(allcoursetimeobject[key]).forEach(function(k) {
if (k != "hours" && k != "days") {
delete allcoursetimeobject[key][k];
}
});
});
console.log(allcoursetimeobject);
Or Maybe, you want to delete properties in the allcoursetimeobject object itself
Then:
var allcoursetimeobject = {
hours: 10,
days: 20,
test: "Delete This"
};
Object.keys(allcoursetimeobject).forEach(function(key) {
if (key != "hours" && key != "days") {
delete allcoursetimeobject[key];
}
});
console.log(allcoursetimeobject);
Hope that helps!

Group multiple elements in array with JavaScript

I have an array
[
{ price: 10 },
{ price: 10 },
{ price: 10 },
{ price: 10 },
{ price: 20 },
{ price: 20 },
]
and I want it transformed into
[
{ numElements: 4, price: 10 },
{ numElements: 2, price: 20 },
]
I have tried using arr.reduce((prev, curr) => ..., []) to accomplish this, but I can't figure out how to do it.
A traditional method might use a for/loop to wrangle the data, but these days JavaScript has a number of functional methods that can help. This code uses reduce and map. To get your data in the format you want is a two stage process.
First, use reduce to create a hash table using the price as a key (because you know the each price is going to be unique:
const obj = arr.reduce((p, c) => {
// If price exists as a key its value by 1
// otherwise set it to 1.
p[c.price] = ++p[c.price] || 1;
return p;
}, {});
OUTPUT
{
"10": 4,
"20": 2
}
As it stands you've got a perfectly good object that you can access by the key/price and I would probably just stop there:
obj['10'] // 4
But if you want to get that data into the format in your question, map over the object keys to return an array of new objects.
const out = Object.keys(obj).map(key => {
return { price: +key, numElements: obj[key] };
});
DEMO
var hash = {}, result = [];
arr.forEach(function(el){
if(hash[el.price]){
hash[el.price].numElements++;
}else{
result.push(hash[el.price]={price:el.price,numElements:1});
}
});
Run
May use a hash table for price lookup. Or with reduce and find:
arr.reduce((res,{price})=>
(( res.find(el=>el.price===price) || res[res.push({price,numElements:0})-1] )
.numElements++,res)
);
Run
You can use try this:
let arr = [
{ price: 10 },
{ price: 10 },
{ price: 10 },
{ price: 10 },
{ price: 20 },
{ price: 20 },
]
let result = []
let counter = {}
arr.forEach( el => {
if (!counter[el.price]) counter[el.price] = 1
else counter[el.price]++
console.log(counter[el.price])
})
for (let id in counter) {
result.push({numElements: counter[id], price: id})
}
Assuming that the data comes sorted on price property, with a single .reduce() you may do as follows;
var data = [{ price: 10 }, { price: 10 }, { price: 10 }, { price: 10 }, { price: 20 }, { price: 20 }],
result = data.reduce((r,d,i) => i ? r[r.length-1].price === d.price ? (r[r.length-1].numElemenets++, r)
: (r.push(Object.assign({}, d, {numElemenets: 1})),r)
: [Object.assign({}, d, {numElemenets: 1})], {});
console.log(result);
You could look up the price in the result array and if not found insert a new object.
var data = [{ price: 10 }, { price: 10 }, { price: 10 }, { price: 10 }, { price: 20 }, { price: 20 }],
grouped = data.reduce((r, { price }) => {
var t = r.find(p => price === p.price);
t || r.push(t = { numElements: 0, price });
t.numElements++;
return r;
}, []);
console.log(grouped);

Categories