What is the easiest way to remove all objects from an array with a particular property = x?
Use _.filter
var result = _.filter(arr, function(item) {
return !("prop" in item);
});
If you want to limit it to the immediate properties of each item, use
var result = _.filter(arr, function(item) {
return !item.hasOwnProperty("prop");
});
It seems like the easiest way would be to use the filter method:
var newArray = _.filter(oldArray, function(x) { return !('prop' in x); });
// or
var newArray = _.filter(oldArray, function(x) { return !_.has(x, 'prop'); });
Or alternatively, the reject method should work just as well:
var newArray = _.reject(oldArray, function(x) { return 'prop' in x; });
// or
var newArray = _.reject(oldArray, function(x) { return _.has(x, 'prop'); });
Update Given your updated question, the code should look like this:
var newArray = _.filter(oldArray, function(x) { return x.property !== 'value'; });
Or like this
var newArray = _.reject(oldArray, function(x) { return x.property === 'value'; });
Related
I implemented an aggregation function but the only problem I have now is that I lost my key: value format e.g [{name:"Apples",val:8},{name:"Banana",val: 9}].
function agrregate(a){
var targetObj = {};
var result;
var b = JSON.parse(JSON.stringify(a));
var trees= b.length;
if(!trees){
trees = 0
}
for (var i = 0; i < trees; i++) {
if (!targetObj.hasOwnProperty(b[i].key)) {
targetObj[b[i].key] = 0;
}
targetObj[b[i].key] += b[i].val;
}
result = JSON.stringify(targetObj);
return result;
}
This is the result i get when agrregate function completes.
{"Apple":8,"Banana":9}
Instead of
{name:"Apple", val:8}, {name:"Banana", val:9}
Use a reducer to aggregate. You don't need to do stuff with JSON stringify/parse.
To get back to an array of objects, you use map and Object.keys
var test = [{name:"Apples",val:5},{name:"Banana",val: 9},{name:"Apples",val:3}]
var aggregate = function(arr) {
return arr.reduce(function(result, obj) { // Create one object (result)
result[obj.name] = (result[obj.name] || 0) + obj.val; // Add a new key/or increase
return result // Return the object
}, {});
};
var wrap = function(obj) {
return Object.keys(obj) // Create an array of keys
.map(function(key) {
return { // Specify the format
name: key,
val: obj[key]
};
});
};
console.log(aggregate(test));
console.log(wrap(aggregate(test)));
I have one object that I had to take apart into two arrays to handle properly.
It looked like this:
{
city:"stuttgart",
street:"randomstreet",
...
}
Since it needs to fit a certain directive I had to convert it to:
[
{key:"city", value:"stuttgart"}
{key:"street", value:"randomstreet"},
...
]
for this I first used
var mapFromObjectWithIndex = function (array) {
return $.map(array, function(value, index) {
return [value];
});
};
var mapFromObjectWithValue = function (array) {
return $.map(array, function(value, index) {
return [index];
});
});
to create two arrays, one containing the old key, the other one is holding the old value. Then I created another, two dimensional array map them into a single array doing this
var mapToArray = function (arrayValue, arrayIndex) {
var tableData = [];
for (var i = 0; i<arrayIndex.length; i++){
tableData[i] = {key:arrayIndex[i] , value:arrayValue[i]};
}
return tableData;
};
(maybe I have already messed up by here, can this be done any easier?)
Now, I use the array (tableData) to display the data in a form. The value fields can be edited. In the end, I want to convert the array (tableData) to its original. (see first object)
Please note, that the original object doesn't only contain strings as values, but can also contain objects as well.
I think conversion can be definitely easier:
var obj = {
city:"stuttgart",
street:"randomstreet",
};
var tableData = Object.keys(obj).map(k => {return {key: k, value: obj[k]}});
console.log(tableData);
var dataBack = {};
tableData.forEach(o => dataBack[o.key] = o.value);
console.log(dataBack);
What do you want to do with objects? Do you want to expand them as well? If yes you can do something like this (and it works with nested objects as well):
var obj = {
city:"stuttgart",
street:"randomstreet",
obj: {a: 'a', b: 'b'},
subObject: {aha: {z: 'z', y: 'y'}}
};
function trasformToTableData(obj) {
if (typeof obj !== 'object') return obj;
return Object.keys(obj).map(k => {return {key: k, value: trasformToTableData(obj[k])}});
}
var tableData = trasformToTableData(obj);
console.log(tableData);
function transformBack(obj) {
if (Array.isArray(obj)) {
var support ={};
for (let i = 0; i < obj.length; i++) {
support[obj[i].key] = transformBack(obj[i].value)
}
return support;
}
return obj;
}
var dataBack = {};
tableData.forEach(o => dataBack[o.key] = transformBack(o.value));
console.log(dataBack);
Let's have some fun and turn our object into iterable to do the job as follows;
var input = {city:"stuttgart", street:"randomstreet", number: "42"};
output = [];
input[Symbol.iterator] = function*(){
var ok = Object.keys(this),
i = 0;
while (i < ok.length) yield {key : ok[i], value: this[ok[i++]]};
};
output = [...input];
console.log(output);
This function will map your object to an array when you call objVar.mapToArray(), by using Object.keys() and .map()
Object.prototype.mapToArray = function() {
return Object.keys(this).map(function(v) {
return { key: v, value: this[v] };
}.bind(this));
}
I would do something like this:
var dataObj = {
city:"stuttgart",
street:"randomstreet",
};
function toKeyValue(obj) {
var arr = [];
for (var key in obj) {
if(obj.hasOwnProperty(key)) {
arr.push({'key': key, 'value': obj[key]});
}
}
return arr;
}
var arrayKeyValue = toKeyValue(dataObj);
console.log(arrayKeyValue);
I want to create a function in Javascript which takes an array as argument and returns a list of objects. I have an array like this:
var arr= [10,20,30];
console.log(listFunction(arr));
The result should look like this:
{'val':10, 'restList':{'val':20, 'restList':{'val':30,'restList':'null'}}}
I have tried the forEach() function:
function listFunction(parentArr) {
var listOfObjects = [];
parentArr.forEach(function (entry, thisArg) {
var singleObj = {}
singleObj['val'] = entry;
singleObj['restList'] = singleObj;
listOfObjects[thisArg] = singleObj;
});
return listOfObjects;
};
You need to use a recursive function:
function listFunction(arr){
if(arr.length == 0){
return null;
}else{
return {val: arr[0], restList: listFunction(arr.slice(1,arr.length))};
}
}
This is the Lisp-style recursive list algorithm.
var recursiveList = function (array) {
return recursiveListHelper(arr, {});
};
var recursiveListHelper = function (array, obj) {
if (array.length === 0) //stopping condition
return null;
var car = array[0]; //current element
var cdr = array.slice(1); //rest of list
obj = {val: car};
obj.restList = recursiveListHelper(cdr, obj);
return obj;
};
You mentioned that you wanted to avoid using Array.slice. This solution uses array indexing instead of splitting into subarrays.
var recursiveIndexed = function (array) {
return recursiveIndexedHelper(array, {}, 0);
};
var recursiveIndexedHelper = function (array, obj, index) {
if (index == array.length)
return null;
var car = array[index];
obj = {val: car };
obj.restList = recursiveIndexedHelper(array, obj, index + 1);
return obj;
};
A plunker as example.
How to negate a boolean function?
Such that using something like:
_.filter = function(collection, test) {
var tmp = []
_.each(collection, function(value){
if (test(value)) {
tmp.push(value);
}
})
return tmp
};
var bag = [1,2,3];
var evens = function(v) { return v % 2 === 0};
This is wrong:
// So that it returns the opposite of evens
var result = _.filter(bag, !evens);
result:
[1,3]
Underscore has a .negate() API for this:
_.filter(bag, _.negate(evens));
You could of course stash that as its own predicate:
var odds = _.negate(evens);
then
_.filter(bag, odds);
Try making a function that returns a function:
function negate(other) {
return function(v) {return !other(v)};
};
Used like this:
var result = _.filter(bag, negate(evens));
Or just declare a function when you call it:
var result = _.filter(bag, function(v) {return evens(v)});
I'm trying to do a neat little function for filtering an array of objects so that only object with unique value of a certain property is returned. This function works fine when prop is just a plain property such as "email". But the function does not work when giving nested properties as argument, like "customer.email"
var unique = function (arr, prop) {
var found = [];
return arr.filter(function (obj) {
if (found.indexOf(obj[prop]) < 0) return found.push(obj[prop]);
});
};
reminders = unique(reminders, 'customer.email');
Is there a elegant way to give nested properties as argument, or is this something that should be avoided?
Instead of passing a property name, I would pass in a property function:
var unique = function (arr, prop) {
var found = [];
return arr.filter(function (obj) {
var value = prop(obj);
var result = found.indexOf(value) < 0;
if (result) found.push(value);
return result;
});
};
var reminders = unique(reminders, function (obj) {
return obj.customer.email;
});
Hope that helps.
other version
var unique = function (arr, prop) {
var found = [];
return arr.filter(function (obj) {
var i=0, currentProp;
while (obj && (currentProp=(prop.split("."))[i++]) ) {
obj=obj[currentProp];
}
if (found.indexOf(obj) < 0) return found.push(obj);
});
};
var reminders=[{customer : {email:'test'}},{customer : {email:'vlad'}},{customer : {email:'vlad'}}];
reminders= unique(reminders, 'customer.email');
console.log(reminders);
var reminders=[ {email:'test'}, {email:'vlad'}, {email:'vlad'}];
reminders= unique(reminders, 'email');
console.log(reminders);