Filter and reduce object in javascript - javascript

I am not really sure on how to do this, I have an object that contains several objects. It looks like this :
object {
apps: {
apps1: {
date: "2017-07-05T17:13:53.956Z",
status: false
}
},
apps2: {
date: "2017-07-11T15:15:39.027Z",
status: false
},
apps3: {
date: "2017-07-11T15:36:33.063Z",
status: true
}
}
Now I wanted to sort them by date first which is working :
function getAppStatus(user) {
let newArr = Object.keys(user.apps).reduce(function(a, b) {
return user.apps[a].date > user.apps[b].date ? a : b;
});
But I only want to sort the one that have status === false so basically I want to delete the apps3 if the status is true and then sort the rest by date.
Any ideas ?
thanks !

Try something like
var newArr = Object.keys(user.apps)
// convert the object to an array by key.
.map(function (key) { return user.apps[key]; })
// get apps with status === false.
.filter(function (app) { return !app.status; })
// sort by date. Since the date is stored as a string, use localeCompare.
.sort(function (a1, a2) { return a1.date.localeCompare(a2.date)); });

Related

Typescript array object filter

I'm trying to filter a array object in angular 5, this is my object
{
"id_record": 2,
"groupName": "PD",
"count": 15,
"userList": [{
"name": "jeffhua",
"nEmail": "jeffhua#abc.com"
},
{
"name": "joey",
"nEmail": "joey#abc.com"
},
{
"name": "angelagosto",
"nEmail": "angelagosto#abc.com"
}
]
}
and here is my filter code
return items.filter(it => {
return it.userList.filter(dit => {
return dit.name.toLowerCase().includes(filterText)
});
});
What could be wrong?
Use some instead of inner filter
return items.filter(it => {
return it.userList.some(dit => {
return dit.name.toLowerCase().includes(filterText)
});
});
In your filter code, the second filter returns an array :
return it.userList.filter(dit => {
return dit.name.toLowerCase().includes(filterText)
});
// returns array
and the filter method awaits a boolean to be returned. Try the following :
return items.filter(it => {
return it.userList.filter(dit => {
return dit.name.toLowerCase().includes(filterText);
}).length !== 0;
});
In my code snippet, I check if the inner filter result (an array) is empty or not. If not, you return true to the parent filter, which will keep the current object in the resulting array.
Breakdown (edit)
The following returns a boolean, checking if the name in lowercase of one of your user contains filterText.
return dit.name.toLowerCase().includes(filterText);
Then, this block returns an array containing all the values that returned true in the condition explained before :
return it.userList.filter(dit => {
return dit.name.toLowerCase().includes(filterText);
})
But, for the parent part of the code snippet to filter the array, it needs a boolean as return value :
return items.filter(it => {
return // expect boolean
});
Then, the .length !== 0 at the end of :
it.userList.filter(dit => {
return dit.name.toLowerCase().includes(filterText);
})
makes it a boolean which should be reflecting the condition you're wanting.
In full (and commented) :
// filter returns an array filtered by the method
return items.filter(it => {
// awaits a boolean return value, with filter returning an array.
return it.userList.filter(dit => {
// filter awaits a boolean as return value AND returns a boolean --> ok for filter
return dit.name.toLowerCase().includes(filterText);
}).length !== 0; // filter has returned an array, we cast it to boolean while checking if its length is greater than 0.
});

Return property of Object instead of Object itself when using find()

I am trying to get the value of the client using the client's name and for some reason I get back the full client object:
function createBank(clients) {
return {
clients: clients,
safeBoxValue: function() {
return this.clients.reduce(function(sum, client) {
return sum + client.value;
}, 0);
},
getclientValue: function(clientName) {
return this.clients.find(function(client) {
if (client.name === clientName) {
return client.value;
}
});
}
}
}
var clients = [
{name: "John", value: 349},
{name: "Jane", value: 9241},
{name: "Jill", value: 12734},
]
var bank = createBank(clients);
bank.safeBoxValue(); // 22324
bank.getclientValue('Jill'); // {"name":"Jill","value":12734}
Anybody knows why? Thanks!
array.find() works by passing in a function that returns a Boolean value to determine whether the object is the one you're looking for. Your function is working despite the code because you are returning a value that is 'truthy' when you return client.value.
The function would work exactly the same if you had just done this:
getclientValue: function(clientName) {
return this.clients.find(function(client) {
return client.name === clientName
});
}
It will go through the array until you return true and then pass you the element, in this case the whole object, you just found. To only get the value, you will need to return it separately:
getclientValue: function(clientName) {
var found = this.clients.find(function(client) {
return client.name === clientName
});
return found && found.value
}
Just remember find() only returns the first value found.

Object push Firebase, how to remove key names from pushed items

I have this Object.key code that pushes all items:
const cloned_items = [];
Object.keys(items).sort().map(key => {
let item = {
[`item-${uid}`]: {
item: false
}
}
cloned_items.push({ ...item });
});
database.ref('/app/items').update({
...cloned_items
})
but this produces following result:
"0" : {
"timeslot-87dah2j" : {
item: false
}
},
"1" : {
"timeslot-7s1ahju" : {
item: false
}
}
instead of:
"timeslot-87dah2j" : {
item: false
},
"timeslot-7s1ahju" : {
item: false
}
any idea ?
It seems like you want to create a plain object, not an array.
In that case:
const cloned_items = Object.assign(...Object.keys(items).map(uid =>
({ [`item-${uid}`]: {item: false} })
));
NB: sorting is of no use when creating an object -- its keys are supposed to have no specific order.
You're creating an array of objects. Seems like you want to use .reduce() to create a single object from the array.
const cloned_items = Object.keys(items).sort().reduce((obj, key) =>
Object.assign(obj, { [`item-${uid}`]: { item: false } })
, {});
Your code doesn't show where uid is coming from, but I assume you meant key there, along with timeslot instead of item.
You may find Object.defineProperty to be cleaner, though you'll need to set up the property descriptor as you want it.
const cloned_items = Object.keys(items).sort().reduce((obj, key) =>
Object.defineProperty(obj, `item-${uid}`, {value:{item: false}})
, {});

React: Calling filter on Object.keys

A React component is passed a state property, which is an object of objects:
{
things: {
1: {
name: 'fridge',
attributes: []
},
2: {
name: 'ashtray',
attributes: []
}
}
}
It is also passed (as a router parameter) a name. I want the component to find the matching object in the things object by comparing name values.
To do this I use the filter method:
Object.keys(this.props.things).filter((id) => {
if (this.props.things[id].name === this.props.match.params.name) console.log('found!');
return (this.props.things[id].name === this.props.match.params.name);
});
However this returns undefined. I know the condition works because of my test line (the console.log line), which logs found to the console. Why does the filter method return undefined?
Object.keys returns an array of keys (like maybe ["2"] in your case).
If you are interested in retrieving the matching object, then you really need Object.values. And if you are expecting one result, and not an array of them, then use find instead of filter:
Object.values(this.props.things).find((obj) => {
if (obj.name === this.props.match.params.name) console.log('found!');
return (obj.name === this.props.match.params.name);
});
Be sure to return that result if you use it within a function. Here is a snippet based on the fiddle you provided in comments:
var state = {
things: {
1: {
name: 'fridge',
attributes: []
},
2: {
name: 'ashtray',
attributes: []
}
}
};
var findThing = function(name) {
return Object.values(state.things).find((obj) => {
if (obj.name === name) console.log('found!');
return obj.name === name;
});
}
var result = findThing('fridge');
console.log(result);
You need to assign the result of filter to a object and you get the result as the [id]. You then need to get the object as this.props.things[id]
var data = {
things: {
1: {
name: 'fridge',
attributes: []
},
2: {
name: 'ashtray',
attributes: []
}
}
}
var name = 'fridge';
var newD = Object.keys(data.things).filter((id) => {
if (data.things[id].name === name) console.log('found!');
return (data.things[id].name === name);
});
console.log(data.things[newD]);

filter JSON by two different values

I'm using a function to filter a JSON file based on the value of the year key, like so:
function filterYr(json, key, value) {
var result = [];
for (var year in json) {
if (json[year][key] === value) {
result.push(json[year]);
}
}
return result;
}
I'm then setting a default:
var chooseYear = filterYr(json, 'year', "2000");
However there's also a dropdown, so the JSON file can be filtered onchange of the dropdown select option.
My question is, can I use this same function to filter the same JSON file by another value, too?
So for instance, I also want to filter by the key 'type.'
If it were a new function it'd be:
function filterType(json, key, value) {
var result = [];
for (var type in json) {
if (json[type][key] === value) {
result.push(json[type]);
}
}
return result;
}
But how do I combine that into one function?
And then how do I set a default that passes both the 'type' and the 'year' to the function?
Is that possible?
Thank you and let me know if I can provide more detail if this isn't clear.
PS- I'd prefer to just use javascript and not a library, if possible.
If your data structure is like below, your current function just works well
var items = [
{
year: 2000,
type: 'type1'
},
{
year: 2001,
type: 'type2'
}
];
function filterYr(json, key, value) {
var result = [];
for (var year in json) {
if (json[year][key] === value) {
result.push(json[year]);
}
}
return result;
}
filterYr(items, 'type', 'type2'); //[ { year: 2001, type: 'type2' } ]
filterYr(items, 'year', 2000); //[ { year: 2000, type: 'type1' } ]
You just need to use a more general name for your function and year variable
You can modify the function so it accepts an object as criterion for filtering. The following function accepts an object with n number of properties:
function findWhere(collection, props) {
var keys = Object.keys(props), // get the object's keys
klen = keys.length; // cache the length of returned array
return collection.filter(function(el) {
// compare the length of the matching properties
// against the length of the passed parameters
// if both are equal, return true
return keys.filter(function(key) {
return el[key] === props[key];
}).length === klen;
})
}
var filteredCollection = findWhere(arrayOfObjects, {
type: 'foo',
anotherProp: 'aValue'
});

Categories