I have some data
var data = [
{type: "A", role:[1,2]},
{type: "B", role:[2]},
{type: "C", role:[2,3]},
{type: "D", role:[3]}
];
I'm trying to sortBy 'role' using underscore.js
var groups = _(data).groupBy(function(el){
return el.role
}
);
Is there a easy way to get reapeated data like this
1: {
{type:"A" ...}
},
2: {
{type:"A" ...},
{type:"B" ...},
... etc
not like this http://jsbin.com/IzEwUkim/2/edit
You can, as usual, do it by hand with _.reduce, something like this:
var groups = _(data).reduce(function(memo, o) {
_(o.role).each(function(i) {
memo[i] = memo[i] || [ ];
memo[i].push(o);
});
return memo;
}, { });
Demo: http://jsfiddle.net/ambiguous/HDE3c/
You could use a plain for loop instead of _.each to iterate over the roles of course.
_.groupBy isn't going to work here as the function/key is always a single value so I think you're stuck unwrapping the role arrays by hand.
I know you asked for underscore, but here's native js:
var map = {};
data.forEach(function(obj){
obj.role.forEach(function(roleVal){
(map[roleVal] = map[roleVal] || []).push(obj);
});
});
console.log(map);
Related
I have data in a JSON array that looks like this:
[{"TEACHER":3.7},{"STUDENT":1.9}]
My desired output is a JSON array that looks like this:
var statements = [
{
name: "TEACHER",
value: 3.7
},
{
name: "STUDENT",
value: 1.9
}
];
How can I "unstack" the data I have to add the variable labels like I want?
This is what I came up with. There might be a more elegant way to do this though.
var x = [{"TEACHER":3.7},{"STUDENT":1.9}];
console.log(unstack(x));
function unstack(stacked){
var unstacked = [];
stacked.forEach((element) => {
unstacked.push({
name: Object.keys(element)[0],
value: Object.values(element)[0]
});
});
return unstacked;
}
Is it the only key your original object has? If that's the case, you can use the only item Object.keys() or Object.entries() return. If there are other attributes you could look for a match in the key and process it accordingly.
const input = [{"TEACHER":3.7},{"STUDENT":1.9}];
const output = [];
input.forEach(item => {
const key = Object.keys(item)[0];
output.push({name: key, value: item[key]});
});
console.log(output);
Sorry, it is probably quite trivial, still I can't find a solution for:
I have an object that contains the following elements:
0: "A"
1: "B"
2: "C"
I would like to use the map() function to convert it to something like this:
0: {name: "A"}
1: {name: "B"}
2: {name: "C"}
If I use this:
this.xxx = this.operations.map(obj => obj.name);
console.log(this.xxx);
or this:
this.xxx = this.operations.map(obj => {name:obj} );
console.log(this.xxx);
the elements of xxx are undefined.
When you write
someArray.map(obj => {
//this is a code block, not an object definition
} )
the curly braces enclose a code block, not an object literal.
If you want an arrow function to return an object, JS requires you to wrap the object literal with parentheses in order to correctly parse your intent.
As such:
this.operations.map(obj => ({name: obj}) )
will fix your mapping.
Alternatively, if you want to do something more complex, use a codeblock and return the value:
this.operations.map(obj => {
// do some calculations
return {name: obj};
})
If I understood you would like to turn them to object? That's how you could do:
var x = ["A", "B", "C"];
console.log(x.map(obj => {return {name: obj}}));
Map object values to array of objects and then convert it into object using Object.assign
var obj = {
0: "A",
1: "B",
2: "C",
};
console.log(Object.assign({},Object.values(obj).map(a => ({ name: a }))));
First of all, if you have object, not sure how you can work with map function overall, since it's array prototype function. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map however if its array you should try this:
const operations = [ "A", "B", "C"]
const xxx = operations.map(obj => ({name:obj}) );
console.log(xxx)
you were missing wrapping brackets, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Advanced_syntax
but if its really an object then this should work (not sure about performance):
const operations = {
0: "A",
1: "B",
2: "C",
}
const xxx = {}
Object.entries(operations).forEach(entry => {
xxx[entry[0]] = { name: entry[1] }
});
console.log(xxx)
Try this,with Object.entries
let obj = {
0: "A",
1: "B",
2: "C"
}
let result = Object.entries(obj).map(([,name]) => ({
name
}));
console.log(result)
Since the object is similar to an array you can add the length property making it array like in this way. Then you can convert it to a real array using Array.from passing the transformation function as the second argument:
const input = {
0: "A",
1: "B",
2: "C"
}
const result = Array.from(
{ ...input, length: Object.keys(input).length },
item => ({ name: item })
)
console.log(result)
You can't use .map() to produce an object, since it always returns an array.
Your best bet would be to get the entries in the object, then use .reduce() on it, like so:
const operations = {
0: 'A',
1: 'B',
2: 'C',
}
const res = Object.entries(operations)
.reduce((acc, [key, val], i) => { acc[i] = { [key]: val }; return acc },{})
console.log(res)
Hello I am new to Javascript and NodeJS, but I need to delete a object in a array with a boolean in the list. There are 3 friends in the list and 2 friends with isEvil = true; So i need to delete 2 friends and the output must be 1.
This is what i tried.
MyTry 1:
_.each(user.friends, function(friend) {
if(friend.isEvil){
delete friend;
}
});
console.log(user.friends.length); //output is 3
If I do this it will delete all the properties but there is still a empty object there: MyTry 2:
_.each(user.friends, function(friend) {
if(friend.isEvil){
delete f.property1;
delete f.property2;
}
});
console.log(user.friends.length); //output is 3
And the last one i tried is:
_.each(user.friends, function(friend, key) {
if(friend.isEvil){
delete user.friends[key];
}
});
console.log(user.friends.length); //output is 3
just use the _.filter(list, predicate, [context]) function provided with underscore:
_.filter(user.friends, function(friend){
return !friend.isEvil;
});
for more info: http://underscorejs.org/#filter
Filter the users friend like
user.friends.filter(function (friend) {
return !friend.isEvil;
});
var frieds = [{ name: 1, isEvil: false }, { name: 2, isEvil: true }, { name: 3, isEvil: true }];
var notEvil = friends.filter(function (friend) {
return !friend.isEvil;
});
console.log(notEvil);
To get rid of evil friends you could use underscore's reject function:
var niceFriends = _.reject(friends, 'isEvil');
var friends = [
{ id: 'mickey', isEvil: false },
{ id: 'donald', isEvil: true },
{ id: 'minnie', isEvil: false }
];
var niceFriends = _.reject(friends, 'isEvil');
document.getElementById('result').textContent = JSON.stringify(niceFriends);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.2/underscore.js"></script>
<p>
<pre id="result"></pre>
</p>
Delete operator leaves your array with undefined on the place of removed element (see delete). I believe you should use Splice method to remove elements.
Or you might just use built in Underscores methods to filter your array (e.g. filter), like:
user.friends = _.filter(user.friends, function(item) {
return !item.isEvil;
};
try this,basically you iterate though you array and splice all unwanted objects:
for(var i in user.friends){
if(user.friends[i].isEvil){
user.splice(i,1)
}
}
I am trying to acheive something similar to SQL table join,
in the most elegant (functional) way, preferably with underscore.js,
so no for loops please.
I need to merge objects from two different arrays, matched upon a common identifier.
For example, given:
var basic = [{
id: '1',
name: 'someName',
},
{...} ]
var ext= [{
id: '1',
job: 'someJob',
},
{...} ]
Result should be:
var combined = [{
id: '1',
name: 'someName',
job: 'someJob',
},
{...} ]
Thanks!
Map, findWhere and extend should do the trick:
var combined = _.map(basic, function(base){
return _.extend(base, _.findWhere(ext, { id: base.id} ));
});
Edit:
If performance is an issue create a hash of the extended values:
var extHash = _.reduce(ext, function(memo, extended, key){
memo[extended.id] = extended;
return memo;
}, {});
and use like so:
var combined = _.map(basic, function(base){
return _.extend(base, extHash[base.id]);
});
Fiddle
NO LOOP : http://jsfiddle.net/abdennour/h3hQt/2/
basic=basic.sort(function(a,b){return a.id-b.id});
ext=ext.sort(function(a,b){return a.id-b.id});
var combined=basic.map(function(e,i){return inherits(e,ext[i]) });
Known that ,inherits are as following:
function inherits(base, extension)
{
for ( var property in base )
{
extension[property] = base[property];
}
return extension ;
}
Imagine I have a nested array structure.
var nested = [ [1], [2], [3] ];
Using underscore.js, how would I produce a flattened array?
In C# you would use Enumerable.SelectMany like this:
var flattened = nested.SelectMany(item => item);
Note that the lambda in this case selects the nested item directly, but it could have been any arbitrary expression.
In jQuery, it's possible to just use:
var flattened = $.map(nested, function(item) { return item; });
However this approach doesn't work with underscore's map function.
So how would I get the flattened array [1, 2, 3] using underscore.js?
If you have a slightly more complicated array, say one coming from JSON, you can take advantage of the pluck method as well, extracting the specific property you are interested in, similar to parents.SelectMany(parent => parent.Items);
// underscore version
var allitems = _.flatten(_.pluck(parents, 'items'));
allitems is now the array of all subitems from the parents, [a,b,c,d].
And a JSFiddle showing the same thing.
Or, if you are using lodash you can do the same thing by using the _.flatMap function which is available since version 4. Cred to Noel for pointing it out in the comments.
var parents = [
{ name: 'hello', items: ['a', 'b'] },
{ name: 'world', items: ['c', 'd'] }
];
// version 1 of lodash, straight up
var allitems = _.flatMap(parents, 'items');
logIt('straight', allitems);
// or by wrapping the collection first
var allitems = _(parents)
.flatMap('items')
.value();
logIt('wrapped', allitems);
// this basically does _(parents).map('items').flatten().value();
function logIt(wat, value) {
console.log(wat, value)
}
<script src="https://cdn.jsdelivr.net/lodash/4.16.6/lodash.min.js"></script>
<pre id="result"></pre>
In case you want to do more stuff and don't want to chain operators, you can use the flow function to get the same effect. This is useful if you are using TypeScript and importing each operator individually, since you can then optimize your final payload.
const parents = [
{ name: 'hello', items: ['a', 'b'] },
{ name: 'world', items: ['c', 'd'] }
];
logIt('original', parents);
const result = _.flow(
(collection) => _.flatMap(collection, (item) => item.items),
(flattened) => flattened.filter((item) => item !== 'd')
)(parents);
logIt('result without "d"', result);
function logIt(wat, value) {
console.log(wat, value);
}
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.11/lodash.min.js"></script>
<pre id="result"></pre>
var nested = [ [1], [2], [3] ];
var flattened = _.flatten(nested);
Heres a fiddle
We can also make Patrick's solution into a mixin so that it becomes chainable:
_.mixin({
selectMany: function(collection, iteratee=_.identity) {
return _.flatten(_.map(collection, iteratee));
}
});
Examples:
let sample = [{a:[1,2],b:'x'},{a:[3,4],b:'y'}];
console.log(_.selectMany(sample, 'a')); // [ 1, 2, 3, 4 ]
console.log(_.chain(sample).selectMany(o => o.a).filter(a => a % 2 === 0).map(a => a * 3).value()); // [ 6, 12 ]
I couldn't find any methods in lodash that work quite like SelectMany, so I created one using pure JS:
Array.prototype.selectMany = function(fn) {
return Array.prototype.concat(...this.map(fn));
};
Boom.
> console.log([{a:[1,2],b:'x'},{a:[3,4],b:'y'}].selectMany(o => o.a));
[ 1, 2, 3, 4 ]