I have a use case where I have an object of varying values, and I need to get all of these keys that have a specific value. For instance, here is a sample object:
myObject = {
Person1: true,
Person2: false,
Person3: true,
Person4: false
};
The key names will vary, but the valid values are true or false. I want to get an array of the names that have a value of true:
myArray2 = [
'Person1',
'Person3
];
I've been trying to use various lodash functions in combination such as _.key() and _.filter, but with no luck. How can I accomplish this? I'm open to pure JS or Lodash options.
UPDATE: I accepted mhodges' answer below as the accepted answer, although others gave me the same answer. Based on that, I came up with a Lodash version:
var myArray = _(myObject).keys().filter(function(e) {
return myObject[e] === true;
}).value();
If I understand your question correctly, you should be able to use basic .filter() for this.
myObject = {
Person1: true,
Person2: false,
Person3: true,
Person4: false
};
var validKeys = Object.keys(myObject).filter(function (key) {
return myObject[key] === true;
});
Since Lodash was tagged: With pickBy the values can be filtered (and the keys obtained with _.keys ):
var myArray2 = _.keys(_.pickBy(myObject));
var myObject = { Person1: true, Person2: false, Person3: true, Person4: false };
var myArray2 = _.keys(_.pickBy(myObject));
console.log(myArray2 );
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Use Object.keys():
var object = {
1: 'a',
2: 'b',
3: 'c'
};
console.log(Object.keys(object));
Alternative solution:
var keys = [];
for (var key in object) {
if (object.hasOwnProperty(key)) {
keys.push(key);
}
}
console.log(keys);
Don't forget to check a key with the help of hasOwnProperty(), otherwise this approach may result in unwanted keys showing up in the result.
You can do this with Object.keys() and filter().
var myObject = {
Person1: true,
Person2: false,
Person3: true,
Person4: false
};
var result = Object.keys(myObject).filter(function(e) {
return myObject[e] === true;
})
console.log(result)
ES6 version with arrow function
var result = Object.keys(myObject).filter(e => myObject[e] === true)
Related
I'm really stuck on how to return a simple true/false IF my object contains a key with a true value. I do not want to return the key or value itself, just an assertion that it does contain a true value.
E.g
var fruits = { apples: false, oranges: true, bananas: true }
There's a true value in this object. I don't care which one is true... I just want to be able to return true because there is a true value.
My current solution returns ["oranges", "bananas"] not true
Object.keys(fruits).filter(function(key) {
return !!fruits[key]
})
As Giuseppe Leo's answer suggests, you can use Object.values (keys aren't important here) to produce an array of the object's values to call Array#includes on:
const fruits = {apples: false, oranges: true, bananas: true};
console.log(Object.values(fruits).includes(true));
// test the sad path
console.log(Object.values({foo: false, bar: 42}).includes(true));
If Object.keys is permitted but Object.values and includes aren't, you can use something like Array#reduce:
var fruits = {apples: false, oranges: true, bananas: true};
console.log(Object.keys(fruits).reduce((a, e) => a || fruits[e] === true, false));
If you don't have access to anything (or don't like that the reduce approach above doesn't short-circuit), you can always write a function to iterate through the keys to find a particular target value (to keep the function reusable for other targets than true):
function containsValue(obj, target) {
for (var key in obj) {
if (obj[key] === target) {
return true;
}
}
return false;
}
var fruits = {apples: false, oranges: true, bananas: true};
console.log(containsValue(fruits, true));
As you want to know if any of the values is true:
Object.values(fruits).includes(true)
Try with Array.prototype.some():
The some() method tests whether at least one element in the array passes the test implemented by the provided function.
var fruits = { apples: false, oranges: true }
var r = Object.keys(fruits).some(function(key) {
return !!fruits[key]
})
console.log(r);
Though, instead of Object.keys(), it is better to use Object.values() to iterate the objects value directly:
The Object.values() method returns an array of a given object's own enumerable property values, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).
var fruits = { apples: false, oranges: true }
var r = Object.values(fruits).some(f => f)
console.log(r);
You could check with Boolean as callback for Array#some.
const has = o => Object.values(o).some(Boolean);
var a = {},
b = { oranges: true, apples : false },
c = { oranges: false, apples : false };
[a, b, c].forEach(o => console.log(has(o)));
I have state object as:
this.state = {
letterType: {},
letterTag: {},
departmentName: {},
assignedOfficer: {}
}
and I have an another object sortFilters as:
sortFilters = {
letterType: {
0: "letterType1",
1: "letterType2"
},
letterTag: {},
departmentName: {
0: "dept1"
},
assignedOfficer: {}
}
now what I want is to create a newState object (probably using es6 reduce()) which will be created based on sortFilters object such as:
this.newState = {
letterType: {
letterType1: true,
letterType2: true
},
letterTag: {},
departmentName: {
dept1: true
},
assignedOfficer: {}
}
I think this is possible using es6 reduce() but I am not able to get it to work.
As described, your problem is a use case for Object.assign, since you just want to copy the contents of four objects (on sortFilters) into your state object. You'd either do it manually:
Object.assign(this.newState.letterType, sortFilters.letterType);
Object.assign(this.newState.letterTag, sortFilters.letterTag);
Object.assign(this.newState.departmentName, sortFilters.departmentName);
Object.assign(this.newState.assignedOfficer, sortFilters.assignedOfficer);
...or in a loop:
for (const name of Object.keys(sortFilters)) {
Object.assign(this.newState[name], sortFilters[name]);
}
That merges the entries from the sortFilters objects with the ones in this.newState. If you want to replace them instead, you'd use assignment (and probably a shallow copy, but that depends on how sortFilters is used later):
this.newState.letterType = Object.assign({}, sortFilters.letterType);
this.newState.letterTag = Object.assign({}, sortFilters.letterTag);
this.newState.departmentName = Object.assign({}, sortFilters.departmentName);
this.newState.assignedOfficer = Object.assign({}, sortFilters.assignedOfficer);
or
for (const name of Object.keys(sortFilters)) {
this.newState[name] = Object.assign({}, sortFilters[name]);
}
Note that Object.assign does a shallow copy; if any of these objects are nested, you'll need something else.
As of ES2018, you can use property spread when creating the new objets instead of Object.assign:
for (const name of Object.keys(sortFilters)) {
this.newState[name] = {...sortFilters[name]};
}
There are other methods to achieve the same, as reduce is used over arrays. But if using reduce is a practice, then Yes that is also possible, a rough way could be like the following, where we can use reduce over keys of objects, which is an array.
let state = {letterType: {},letterTag: {},departmentName: {},assignedOfficer: {}}
let sortFilters = {letterType: {0: "letterType1",1: "letterType2"},letterTag: {},departmentName: {0: "dept1"},assignedOfficer: {}}
let newState = Object.keys(state).reduce(function(prev, current) {
let val = sortFilters[current]
if (!val) {
prev[current] = state[current]
} else {
prev[current] = Object.keys(val).reduce(function (p, c) {
p[val[c]] = true
return p
}, {})
}
return prev
}, {})
console.log(newState)
For more details about reduce and Object.keys, please refer to Mozilla Developer Network's documentation.
Not sure what "state" or this.state means in this context...React? Anyhow, tt looks like you just want to simply unpack certain properties and manipulate them. If so destructuring assignment might help. Refer to this article section on Destructuring Nested Objects and this section on Nested object and array destructuring
Demo
let sortFilters = {
letterType: {
0: "letterType1",
1: "letterType2"
},
letterTag: {},
departmentName: {
0: "dept1"
},
assignedOfficer: {}
}
// Making a copy of sortFilters
let final = JSON.parse(JSON.stringify(sortFilters));
// Desruturing final, assigning variables and values
let {
letterType: {
letterType1: letterType1 = true,
letterType2: letterType2 = true
},
letterTag: {},
departmentName: {
dept1: dept1 = true
},
assignedOfficer: {}
} = final;
console.log(letterType1);
console.log(letterType2);
console.log(dept1);
I Have the following object:
var config = {
apps: false,
transfers: false,
approvals: true
};
I want to know how I can use Lodash to go through each of the keys within the config object and find out which key has the first occurrence of value true. In the example above, I expect the output to be approvals. If the value for transfers was true, I expect the output to be transfers.
Basically, I want a more cleaner way to do this:
if (config.apps) {
answer = 'apps';
} else if (config.transfers) {
answer = 'transfers';
} else if (config.approvals) {
answer = 'approvals';
}
Thanks!
You can use _.findKey():
var config = { apps: false, transfers: false, approvals: true };
var answer = _.findKey(config);
console.log(answer);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
Or without lodash, you can use Array.prototype.reduce() with Object.keys():
var config = { apps: false, transfers: false, approvals: true };
var answer = Object.keys(config).reduce(function(answer, key) {
return value = config[key] ? key : answer;
}, '');
console.log(answer);
No lodash required:
var config = {
apps: false,
transfers: false,
approvals: true
};
Object.keys(config).find((key) => {
return config[key];
});
A bit newer method then Object.keys is entries with that you can retrieve both the key and the value
let config = {apps: false, transfers: false, approvals: true}
let [key, value] = Object.entries(config).find(([key, val]) => val)
console.log(key, value)
i'm developing in Javascript and i created folders array that contain objects:
folders = [folder1, folder2, folder3...]
Every object have some properties, one of this is docs that is an array of objects:
docs = [doc1, doc2, doc3...]
...and every object is like this:
doc1.title = 'foo'
doc1.desc = 'bar'
doc1.attr = {new: _.random(0, 1) > 0.5, read: _.random(0, 1) > 0.5}
...
I would like to create a function that extract only docs that have attr = {new: true, read: false}.
I tried some underscore method such as _.each, _.sample, _.find and _.findWhere, but i can't figure out how to get from the main array a sample that contains docs with that attr properties.
Any idea?
Using underscore first flatten the folders and then use where to get what you want:
var result = _.where( _.flatten(folders), {new: true, read: false});
Edited to work with the new structure:
var result = _.chain(folders)
.pluck('docs')
.flatten()
.where({isNew: true, read: false})
.value();
var folders = [
{
docs: [
{
title: 'one',
isNew: true,
read: false
}, {
title: 'two',
isNew: true,
read: true
}
]
},
{
docs:
[
{
title: 'three',
isNew: false,
read: false
}, {
title: 'four',
isNew: true,
read: false
}
]
}
];
var result = _.chain(folders)
.pluck('docs')
.flatten()
.where({isNew: true, read: false})
.value();
document.getElementById('result').textContent = JSON.stringify(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.2/underscore.js"></script>
<p>
<pre id="result"></pre>
</p>
Have you tried something like this?
var result = [];
folders.forEach(function(docs) {
result.concat( docs.filter(function(doc) {
return doc.attr.new && !doc.attr.read;
});
});
underscore methods like .find work on arrays which are one level deep:
var temp = [];
_.each(folders , function(docsArray){
var result = _.where(docsArray , {new: true, read: false});
if(result){
temp.concat(result);
}
});
You can achieve what you want without using underscore or lodash,just
Take advantage of the built-in Array.map and Array.filter methods, here is an example :
var myResult = folders.map(function(folder){
return myCustomDocs = folder.filter(function(doc){
return (doc.attr.new && !doc.attr.read);
});
});
console.log(myResult);
What about a regular filter?
Working Demo
(Simply open your browser console and run the fiddle.)
doc1.filter(o => o.attr.new && !o.attr.read)
And you can also simply map() your folders array.
const _folders = folders
.map(doc => doc.filter(o => o.attr.new && !o.attr.read))
You would get on new folders array containing arrays with only new && !read documents. Which you could flatten if needed:
const flatFolders = [].concat.apply([], _folders)
I found a working solution.
Here is my code:
var result = [];
folders.forEach(function(item) {
result = result.concat(_.filter(item.docs, function(doc) {
return doc.isNew === true && doc.read === false;
}));
});
If you have Node.js 5+ or use Babel, you can just do:
folders.reduce((res, arr) => res.concat(arr), []) // flatten folders
.filter(doc => doc.attr.new && !doc.attr.read); // remove all that don't return true
Is there some elegant way of filtering out falsey properties from this object with lodash/underscore? Similar to how _.compact(array) removes falsey elements from arrays
so from
{
propA: true,
propB: true,
propC: false,
propD: true,
}
returning
{
propA: true,
propB: true,
propD: true,
}
Here are two vanilla javascript options:
A.: Iterate over the object's keys and delete those having a falsey value.
var obj = {
propA: true,
propB: true,
propC: false,
propD: true,
};
Object.keys(obj).forEach(key => {
if (!obj[key]) delete obj[key];
});
console.log(obj);
See Object.keys() and Array.prototype.forEach()
B.: Iterate over the object's keys and add truthy values to a new object.
var obj = {
propA: true,
propB: true,
propC: false,
propD: true,
};
var filteredObj = Object.keys(obj).reduce((p, c) => {
if (obj[c]) p[c] = obj[c];
return p;
}, {});
console.log(filteredObj);
See Object.keys() and Array.prototype.reduce()
Lodash 4.0
Lodash 4.0 has _.pick, which takes an array of properties, and _.pickBy which takes a function as an argument and returns an object only containing the keys for which that function returns truthy which is what we want here, so it'd be:
filtered = _.pickBy(obj, function(value, key) {return value;})
Or, since _.pickBy defaults to using _.identity as it's second argument, (and that's essentially what we've written above,) it can just be written as:
filtered = _.pickBy(obj);
Underscore or Lodash prior to version 4.0
In underscore and old versions of lodash, there's just a single _.pick, which has both behaviors of _.pick and _.pickWith from v4. So you can do:
filtered = _.pick(obj, function(value, key) {return value;})
Or more succinctly:
filtered = _.pick(obj, _.identity)
Unfortunately I cannot direclty comment on the posts above yet, so I create this extra post.
Since Lodash v4 the functionality described above has been moved to _.pickBy. With _.identity as default you could also change your code to:
var filtered = _.pickBy(obj);
See this JSBin for a working example.
As partial mentioned in a comment, ES6 provided Object.entries() and in 2019 Object.fromEntries().
Allowing:
Object.fromEntries(Object.entries(obj).filter(([key, value]) => ...))
Ex:
const obj = {
a: 12,
b: 123,
};
const filteredObj = Object.fromEntries(
Object.entries(obj).filter(
([_, value]) => value > 100
)
);
console.log(filteredObj);
// {b: 123}
If you're using lodash, I'd recommend something like this:
var object = {
propA: true,
propB: true,
propC: false,
propD: true,
};
_.pick(object, _.identity);
// →
// {
// propA: true,
// propB: true,
// propD: true
// }
The pick() function generates a new object that includes properties that the callback returns truthy for. So we can just use the identity() function as the callback, since it'll just return each property value.
From lodash 4, we can use pickBy() to get only the value equal to true.
const active = _.keys(_.pickBy(object));
let temp = {
propA: true,
propB: true,
propC: false,
propD: true,
}
let obj = {}
for(x in temp){
if(temp[x] == true){
obj[x] = temp[x]
}
}
console.log(obj)
Using for-in loop we can achieve it something like this.
Another approach
const objFilter = (obj, condition) => {
let newObj = {}
for (const [key, value] of Object.entries(obj)) {
if (condition(value)) {
newObj = { ...newObj, [key]: value }
}
}
return newObj
}
Fire like this:
const newData = objFilter(oldData, (value) => value.marked === false)