Ramdajs keyBy equivalent of lodash - javascript

I have an array that I want to transform into an object. For example:
const arr = [{id: 1, key: ''}, {id: 2, key: ''}];
I want the result to be:
const object = { 1: {id: 1, key: ''}, 2: { id: 2, key: ''}}
With lodash I can use the keyBy function, but I am working with ramda and did not find this functionality there.

In case anyone still finds this via search, the correct answer is indexBy, added in mid-2016.
const list = [
{ id: "xyz", title: "A" },
{ id: "abc", title: "B" },
];
R.indexBy(R.prop("id"), list);
//=> {abc: {id: 'abc', title: 'B'}, xyz: {id: 'xyz', title: 'A'}}
See Also:
Github: Ramda Wiki "What Ramda Function Should I Use?"
Github: Ramda Issue #931 - "sister to groupBy"

You can solve this with very basic reduce function.
function keyBy(entities, id = "id") {
return entities.reduce((acc, entity) => {
acc[entity[id]] = entity;
return acc;
}, {});
}

Related

Get all object pairs into one Array (Javascript)

I have an array like this :
const arr = [{name: "some", category: "Cat1"}, {name: "else", category: "Cat2"}, {name: "stuff", category: "Cat2"}]
I want to create a new array that only have category without pairs like that :
const newArr =[Cat1, Cat2]
and then map over it to render into my JSX Element. I try a lot of stuff but nothing worked Thanks for your help.
Using set object approach is the best approach. As it is already mentioned here I am going to show the other approaches.
Using Object:
You could use Array.prototype.forEach() method with Nullish coalescing operator (??) to do your job.
const arr = [
{ name: 'some', category: 'Cat1' },
{ name: 'else', category: 'Cat2' },
{ name: 'stuff', category: 'Cat2' },
];
const ret = {};
arr.forEach((x) => {
ret[x.category] = ret[x.category] ?? x.category;
});
console.log(Object.values(ret));
Using Map Object:
Map object stores key value pairs with the original insertion order. Although object is similar to map object but map object performs better when you need to do a lot of additions and deletions.
const arr = [
{ name: 'some', category: 'Cat1' },
{ name: 'else', category: 'Cat2' },
{ name: 'stuff', category: 'Cat2' },
];
const map = new Map();
const ret = [];
arr.forEach((x) => {
if (!map.has(x.category)) {
map.set(x.category, true);
ret.push(x.category);
}
});
console.log(ret);
Using Array:
Array.prototype.includes() method checks if the array contains the specified element or not and returns true or false based on that.
const arr = [
{ name: 'some', category: 'Cat1' },
{ name: 'else', category: 'Cat2' },
{ name: 'stuff', category: 'Cat2' },
];
const ret = [];
arr.forEach((x) => {
if (!ret.includes(x.category)) ret.push(x.category);
});
console.log(ret);
Using Reduce Method:
Array.prototype.reduce() method runs the given function for each iteration and reduces the array to a single value.
const arr = [
{ name: 'some', category: 'Cat1' },
{ name: 'else', category: 'Cat2' },
{ name: 'stuff', category: 'Cat2' },
];
const ret = Object.values(
arr.reduce((prev, c) => {
const p = prev;
const key = c.category;
if (!p[key]) p[key] = c.category;
return p;
}, {})
);
console.log(ret);
Try this
const arr = [
{name: "some", category: "Cat1"},
{name: "else", category: "Cat2"},
{name: "stuff", category: "Cat2"}
]
const result = arr.map(a=> a.category);
console.log([...new Set(result)]);
You are looking for something like this:
const arr = [{name: "some", category: "Cat1"}, {name: "else", category: "Cat2"}, {name: "stuff", category: "Cat2"}];
console.log([...new Set(arr.map(x => x.category))]);

Javascript multilevel object spread operator

I have an array of objects, I want all data out from all objects into multiple arrays
const obj = [
{
school: {
name: 'abc',
students: [
{
class: 'A',
name: 'jhon',
},
{
class: 'B',
name: 'Doe',
},
],
},
},
{
school: {
name: 'XYZ',
students: [
{
class: 'C',
name: 'Cena',
},
{
class: 'B',
name: 'Big show',
},
],
},
},
];
I want result something like
[ ["abc", "xyz"], ["A", "B", "C", "B"], ["jhon", "Doe", "Cena", "Big show"]]
Any help will be appreciated
You can make use of reduce and take Object.values of it. While traversing the student array you can take Object.entries of Object. Here is a working example:
var obj = [ { school: { name: 'abc', students: [ { class: 'A', name: 'jhon', }, { class: 'B', name: 'Doe', }, ], }, }, { school: { name: 'XYZ', students: [ { class: 'C', name: 'Cena', }, { class: 'B', name: 'Big show', }, ], }, }];
var result = Object.values(obj.reduce((acc, {school})=>{
acc['schoolname'] = [...(acc['schoolname'] || []), school.name];
school.students.forEach(s=>{
Object.entries(s).forEach(([k,v])=>{
acc[k] = [...(acc[k] || []), v];
});
});
return acc;
},{}));
console.log(result);
Even though this is already answered, I want to share my approach.
It you are able to add a dependency, JSONata is well worth, and it can be used not only to query but also to transform objects with fairly simple queries, that most of the time are way easier to read and understand than regular reducers or maps.
Using JSONata your code will look like this:
jsonata('[ [ $.school.name], [ $.school.students.class ], [ $.school.students.name ] ]').evaluate(obj);
https://try.jsonata.org/zqqQNjYmx
Using the builtin Array methods.
schoolNames =obj.map(function(school){return school.school.name})
students = obj.map(function(school){return school.school.students}).flat()
studentNames = students.map(function(student){return student.name})
studentClass = students.map(function(student){return student.class})

Categorize Similar items into separate objects from Array lists

I have an array of items that I get from API as a response body.
data = [{id: 1, category: "kitchen", name: "noodles"},
{id: 2, category: "general", name: "Wi-Fi"},
{id: 3, category: "sports", name: "Football"},]
I want to iterate over the arrays, and get the data like :
var categorized = {
kitchen: [{id: 1, category: "kitchen", name: "noodles"}],
general : [{id: 2, category: "general", name: "Wi-Fi"}],
sports : [{id: 3, category: "sports", name: "Football"}]
};
Is there any lodash methods, or any ES6 shortcuts for this ?
In answer to your question 'is there a lodash method?' Yes: https://lodash.com/docs/4.17.4#groupBy. For your specific example:
const categorized = _.groupBy(data, 'category');
Edit: You could roll your own groupBy type function with ES6 as in another example. But if you are using lodash anyway this is a whole lot cleaner.
I used array.reduce to get the structure
var data = [{
id: 1,
category: "kitchen",
name: "noodles"
}, {
id: 2,
category: "general",
name: "Wi-Fi"
}, {
id: 3,
category: "sports",
name: "Football"
}]
var newData = data.reduce(function(obj, v, i) {
obj[v.category] = obj[v.category] || [];
obj[v.category].push(v);
return obj;
}, {});
console.log(newData);
In ES6 you could so using:
var newData = data.reduce((obj, v, i)=> {
obj[v.category] = obj[v.category] || [];
obj[v.category].push(v);
return obj;
}, {});
console.log(newData);

ImmutableJs : Updating a List in nested Map

I have a hard reading the ImmutableJS and other questions answers... It seems simple, I have a Map like this :
{
foo: [
{id: 1, name: 'John'},
{id: 2, name: 'Christine'},
{id: 3, name: 'Frank'},
{id: 4, name: 'Jenny'},
]
}
How can i update change "John" to "Johnny" ?
From the docs you can use this:
newMap = oldMap.setIn(['foo', 0, 'name'], 'Johnny');
You pass an array of keys, then the value.

Group by Object ID's in Javascript

I have an array of ID's and organizations like so:
var ids = ['1','2', '3'];
var orgs =
[
{ name: "Org 1", id: 1 },
{ name: "Org 2", id: 2 },
{ name: "Org 3", id: 2 }
]
I want to loop through these to output something like this:
{
1: [
{name: "Org 1", id: 1}
],
2: [
{name: "Org 2", id: 2},
{name: "Org 3", id: 2}
]
}
I tried this without success:
var results = orgs.forEach(function (org) {
if (results[org.id]) {
results.push(org)
} else {
results[org.id] = [org]
};
});
If you don't want to use a library like Underscore, Ramda, or Lo-Dash, then it's simple enough to write this using reduce:
var results = orgs.reduce(function(results, org) {
(results[org.id] = results[org.id] || []).push(org);
return results;
}, {})
you should use underscore and just return your id
http://underscorejs.org/#groupBy
_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); });
// => {1: [1.3], 2: [2.1, 2.4]}
you might also want to take a look at lo-dash

Categories