Is there a better / shorter method to delete properties from objects in an array of objects than the below example. I can use vanilla JS or lodash.
Exmaple function:
function stripObjProps(arr) {
let newArr = _.clone(arr);
for (let i = 0; i < arr.length; i += 1) {
delete newArr[i].isBounded;
delete newArr[i].isDraggable;
delete newArr[i].isResizable;
delete newArr[i].maxH;
delete newArr[i].maxW;
delete newArr[i].minH;
delete newArr[i].minW;
delete newArr[i].resizeHandles;
delete newArr[i].moved;
delete newArr[i].static;
}
return newArr;
}
You can use omit from Lodash to exclude properties:
function stripObjProps(arr) {
return arr.map(item => _.omit(item, ['isBounded', 'isDraggable', 'isResizable', 'maxH', 'maxW', 'minH', 'minW', 'resizeHandles', 'moved', 'static']));
}
const newArray = stripObjProps(originalArray)
Additionally, you can use pick instead of omit. In case of pick you specify only the properties which you want to keep.
I can think of two ways
function stripObjProps(arr) {
let newArr = _.clone(arr);
for (let i = 0; i < newLay.length; i += 1) {
[
"isBounded",
"isDraggable",
"isResizable",
"maxH",
"maxW",
"minH",
"minW",
"resizeHandles",
"moved",
"static"
].forEach(k => delete newArr[i][k]);
}
}
or - assuming newLay is a typo
function stripObjProps(arr) {
return arr.map(item => {
let {
isBounded,
isDraggable,
isResizable,
maxH,
maxW,
minH,
minW,
resizeHandles,
moved,
static,
...ret
} = item;
return ret;
});
}
NOTE: no need for _.clone in this second example, since you aren't doing a deep clone, map returns a new array with a new object (...ret)
However, I don't use lodash, so there may be an even better way with that library
Another way to remove properties with filter and Object entries / fromEntries.
const data = [
{ a: 1, b: 2, c: 3, d: 4, e: 5 },
{ a: 1, b: 2, c: 3, d: 4, e: 5 },
{ a: 1, b: 2, c: 3, d: 4, e: 5 },
];
const excludeKeys = ['b', 'c', 'd'];
const exclude = (obj) =>
Object.fromEntries(
Object.entries(obj)
.filter(([key]) => !excludeKeys.includes(key)));
const result = data.map(exclude);
console.log(result);
.as-console-wrapper {max-height: 100% !important; top: 0}
Related
I need to find an object in an array by a key and value
I'm trying to do a search on an array of objects with for in. but I can not.
My input:
findObject[{ a: 1, b: { c: 2 } }, { a: 1, b: { c: 3 } }, { c: 3 }] //the last argument ({ c: 3 }) is the target
What I'm trying to return:
{ a: 1, b: { c: 3 } }
Note: The array of objects can have any object and the target too
You can use Array.find to find the item in the array whose values contain an object whose c property is 3:
const arr = [{ a: 1, b: { c: 2 } }, { a: 1, b: { c: 3 } }, { c: 3 }]
const result = arr.find(e => Object.values(e).some(k => k.c == 3))
console.log(result)
What the OP is looking for is a find using deep equality (keys and values, including nested keys and values are equal). Even shallow equality is a deep topic in JS and applying it recursively is even deeper.
A fast but flawed idea is comparing JSON encodings for the two objects being compared. I wave a hand at that in the snippet, but prefer to use a utility that has thought through edge cases and probably executes fast.
function isEqual(a, b) {
// not good, but quick to code:
// return JSON.stringify(a) === JSON.stringify(b)
// lodash has put some thought into it
return _.isEqual(a, b)
}
// find the first object in array with a value deeply equal to object
function findObject(array, object) {
return array.find(el => {
return Object.values(el).some(v => isEqual(v, object))
})
}
let array = [{ a: 1, b: { c: 2 } }, { a: 1, b: { c: 3, d: { e: "hi" }} }];
let object = { c: 3, d: { e: "hi" }};
let result = findObject(array, object);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
The OP asks to find the last object of an array as the target in the array up to that point. Adopt as follows...
// array is the array to search plus the last item is the thing to search for
let firstObjects = array.slice(0, -1)
let lastObject = array.at(-1)
let result = findObject(firstObjects, lastObject)
given this input:
const set1 = new Set([10, "someText", {a: 1, b: 2}]);
const set2 = new Set([10, "someText", {a: 1, b: 2}]);
const set3 = new Set([5, "someText", {a: 3, b: 4}]);
const arr = [set1, set2, set3];
combineDupSets(arr);
Wanted result:
[
Set { 10, 'someText', { a: 1, b: 2 } },
Set { 5, 'someText', { a: 3, b: 4 } }
]
I am writing a function to eliminate all the duplicate sets, and since Set() won't check for duplicates when it's an object or set itself, I wrote the following:
function combineDupSets(arr) {
const hold = [];
arr.forEach(set =>{
const copySet = [...set];
const stringify = JSON.stringify(copySet);
if(hold.indexOf(stringify) === -1) {
hold.push(stringify)
}
})
const end = hold.map(item => JSON.parse(item));
const res = end.map(item => item = new Set(item))
return res;
}
Here, I have to use 3 arrays sized O(n) to check for this, and I was just wondering if there's any other solution that is readable that will be more efficient in checking for this for both time and space complexity?
Thank you
Instead of using indexOf in an array, consider putting the sets onto an object or Map, where the key is the stringified set and the value is the original set. Assuming that the values are in order:
function combineDupSets(arr) {
const uniques = new Map();
for (const set of arr) {
uniques.set(JSON.stringify([...set]), set);
}
return [...uniques.values()];
}
This
iterates over the arr (O(n))
iterates over each item inside once (total of O(n * m) - there's no getting around that)
Iterates over the created Map and puts it into an array (O(n))
If the set values aren't necessarily in order - eg, if you have
Set([true, 'foo'])
Set(['foo', true])
that should be considered equal, then it'll get a lot more complicated, since every item in each Set not only has to be iterated over, but also compared against every other item in every other Set somehow. One way to implement this is to sort by the stringified values:
function combineDupSets(arr) {
const uniques = new Map();
for (const set of arr) {
const key = [...set].map(JSON.stringify).sort().join();
uniques.set(key, set);
}
return [...uniques.values()];
}
You could iterate the sets and check the values and treat object only equal if they share the same object reference.
function combineDupSets(array) {
return array.reduce((r, s) => {
const values = [...s];
if (!r.some(t => s.size === t.size && values.every(Set.prototype.has, t))) r.push(s);
return r;
}, []);
}
const
a = { a: 1, b: 2 },
b = { a: 3, b: 4 },
set1 = new Set([10, "someText", a]),
set2 = new Set([10, "someText", a]),
set3 = new Set([5, "someText", b]),
arr = [set1, set2, set3];
console.log(combineDupSets(arr).map(s => [...s]));
I'm searching a for a way to create a function. in which I can pass an object and an array of properties (keys) I want gone. That function will return me a new object that doesn't have the keys I've specified.
function(keys: array, obj: object) {...}
Question is - how do I do that with multiple properties?
I've searched and only found this kind of solution:
const myObject = {
a: 1,
b: 2,
c: 3
};
const { a, ...noA } = myObject;
But it only works if I want to remove only ONE key. What if I want to remove multiple, using an array I just passed? How do I do that without mutating the original array or manually creating copies of it?
You could destructure the object by taking a computed property for unwanted properties.
const
without = (object, keys) => keys.reduce((o, k) => {
const { [k]: _ , ...p } = o;
return p;
}, object),
myObject = { a: 1, b: 2, c: 3 },
keys = ['a', 'b'],
result = without(myObject, keys);
console.log(result);
You can do it using reduce and Object.entries(). You can try this:
const myObject = {
a: 1,
b: 2,
c: 3,
d: 4
};
const removeProps = (object, keys) => {
return Object.entries(object).reduce((a, [key, value]) => (keys.indexOf(key) === -1 ? {...a, [key]: value}: a), {});
}
console.log(removeProps(myObject, ['b']));
console.log(removeProps(myObject, ['b', 'c']));
console.log('Original Object: ', myObject);
.as-console-wrapper{min-height: 100%!important; top: 0}
Above answers are great, I'm sharing my try:
var myObject = { a: 1, b: 2, c: 3, d: 4};
let remove=(obj, arr)=> {
let output=[];
for(const [key, value] of Object.entries(obj)){
if(!arr.includes(key)){
output.push([key,value]);
}
}
return Object.fromEntries(output);
}
console.log(remove(myObject, ['a']));
console.log(remove(myObject, ['a', 'c']));
I want to get this result by some logic through a validate for 'key'.
const validateOfKey= [ 'a', 'b' ]
const pass1 = { a: 3, b: 4 } // true
const pass2 = { a: 3 } // true
const pass3 = { a:3, c:5, .. } // false
const pass4 = { a:3, b:4, c:3...} // false
const pass5 = { d:3, e:5 ...} // false
I can use hasOwnProperty for some case. But in my case, this is a little bit hard for me to make this logic.
Can you recommend some advice for resolving this ? Thank you so much for reading it.
Use Object.keys() to get an array of keys, and check if every key is included in the list of valid keys:
const fn = (validKeys, obj) =>
Object.keys(obj)
.every(k => validKeys.includes(k))
const validateOfKey= ['a', 'b']
console.log(fn(validateOfKey, { a: 3, b: 4 })) // true
console.log(fn(validateOfKey, { a: 3 })) // true
console.log(fn(validateOfKey, { a:3, c:5 })) // false
console.log(fn(validateOfKey, { d:3, e:5 })) // false
You could take a Set and check against the keys from the object.
function has(object, keys) {
return Object.keys(object).every(Set.prototype.has, new Set(keys));
}
const keys = ['a', 'b'];
console.log(has({ a: 3, b: 4 }, keys)); // true - all keys
console.log(has({ a: 3 }, keys)); // true - subset of keys
console.log(has({ a: 3, c: 5 }, keys)); // false - some other key/s
console.log(has({ a: 3, b: 4, x: 3 }, keys)); // false - some other key/s
console.log(has({ d: 3, e: 5 }, keys)); // false - no wanted keys
iterate through all keys in validateOfKey array and check if the given object contains that key. for this we use "key in Object"
var validate = inputObj => {
let validateOfKey = ["a", "b"];
for (let i = 0; i < validateOfKey.length; i++) {
if (!(validateOfKey[i] in inputObj)) {
return false;
}
return true;
}
};
pass any object to above function to check against keys in validateOfKey.
also you can modify validateOfKey as per your needs.
I have an array of objects and I want to find the sum of length of arrays of a certain property(key).
I have this array of objects like
var myArray =
[{
"a" : 1,
"b" : another Array
},
{
"c" : 2,
"b" : another Array
}
.....
]
Is there any way to simplify this below process?
var lengthOfEachObject = myArray.map(function(Obj){
if(Obj.b){
return Obj.b.length;
}
else{
return 0;
}
});
lengthofEachObject.reduce(function(x,y){
return x+y;
})
Answers can also include use of external libraries.
You can use .reduce without .map, this way you can get the total sum by only iterating once over your array. Furthermore, you can use destructing assignment instead of your if statements to set a default value for your b.length if it doesn't exist.
See working example below:
const arr = [{a: 1, b: [1, 2, 3, 4, 5] }, {c: 2, b: [1, 2, 3]}, {e: 3}],
total = arr.reduce((acc, {b={length:0}}) => acc + b.length, 0);
console.log(total);
You can use lodash's _.sumBy():
var myArray = [{"a":1,"b":[1,2,3]},{"c":2,"b":[4,5,6,7,8]},{"c":2}]
var result = _.sumBy(myArray, 'b.length')
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
You could pull out the length with a closure over the wanted key and map this value.
const
length = k => ({ [k]: { length = 0 } = {} }) => length,
add = (a, b) => a + b,
array = [{ a: 1, b: [1, 2, 3, 4] }, { c: 2, b: [1, 2, 3] }];
console.log(array.map(length('b')).reduce(add));
console.log(array.map(length('a')).reduce(add));