I have a list of stores and a list of ids:
var stores = [{id: '1', name: 'first store'}, {id: '2', name: 'second store'}, {id: '3', name: 'third store'}];
var ids = ['1', '2'];
I want to obtain the names of stores that match the ids on the list:
["first store", "second store"]
Here's what I came up with:
var filterStoresById = R.intersectionWith(R.useWith(R.equals, R.view(R.lensProp('id'))));
var extractNames = R.map(R.view(R.lensProp('name')));
extractNames(filterStoresById(stores,ids));
I'm aiming to learn functional programming concepts while at the same time producing code I could use on real life but I don't think my solution is readable nor performant (I'm iterating twice), so what improvements could be made to this code?
Your code is not horrible, only a little less readable than it might be.
First of all, to access a top-level property, especially when you're not reusing the access method, it's much simpler to use prop(name) than view(lensProp(name)). And Ramda has pluck for map(prop).
Second, I find it much easier to read functions built through functional composition than through nested levels of parentheses. I generally prefer pipe to compose, but either would do.
So I would rework your code like this:
var filterStoresById = R.intersectionWith(R.useWith(R.equals, R.prop('id')));
var storeNamesById = R.pipe(filterStoresById, R.pluck('name'));
storeNamesById(stores, ids);
One advantage to this is that you now have the reusable filterStoresById function if you find that you need more than just the names.
The other question is one of performance. There is definitely a penalty for iterating twice. The question is whether it is worth it for the cleaner, more easily refactored code. There are techniques for turning code like this into code that does the same thing but iterating only once and avoiding intermediate containers. You can see these articles on transducers for more information.
But I would avoid worrying about this unless you can demonstrate to yourself that this is actually a performance problem in your application. I assume everyone knows the Knuth misquote "premature optimization is the root of all evil."
innerJoin FTW
const stores = [
{id: '1', name: 'first store'},
{id: '2', name: 'second store'},
{id: '3', name: 'third store'},
]
const ids = ['1', '2']
const f =
R.pipe(R.innerJoin(R.flip(R.propEq('id'))), R.pluck('name'))
console.log(f(stores, ids))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
Related
// foodItems is an array of object where one of it's key is id.
const [id1, id2, id3] = foodItems.map((item) => item.id);
// console.log(id1, id2, id3);
I can get id's by destructuring when array is static by doing above's code. But, How can I get the same id's when the data is coming from database dynamically in this array?
Edit: As Bergi pointed out: this horrible abomination does not even work if used in a different scope than root. But again, even if it had worked, don't do it like that.
Can you try to explain what you are really trying to do with that? Then we might be able to suggest a proper solution.
Old answer for historical reasons:
I don't really know you use-case for this but it generally seems like a bad idea. This is a poor pattern, do not use it, but it should answer your question anyways. So here is an example:
['a', 'b', 'c'].forEach((data, i) => {
this[`id${i+1}`] = data
})
Would lead to this:
id1: a
id2: b
id3: c
For your specific code, assuming the object has an "id" column that should be used (which would still prefix the variable with "id"):
foodItems.forEach((data) => {
this[`id${data.id}`] = data
})
Assuming an object like
const foodItems = [{id: 'foo', value: 'bar'}], it would result in this:
idfoo: {id: 'foo', value: 'bar'}
If you can provide some more context, maybe we could come up with a better solution that actually helps you?
I've recently been using lodash and I just love it. So I'm on a quest to learn it better.
For the past two days I've been trying to figure out how to do the following, without much success: considering an array of objects each with an array of objects in a property props...
let items = [{
name: 'first',
props: [{
id: 1,
name: 'one'
}, {
id: 2,
name: 'two'
}]
}, {
name: 'second',
props: [{
id: 2,
name: 'two'
}]
}, {
name: 'third',
props: [{
id: 1,
name: 'one'
}]
}];
... I'd like to create an array of objects containing each property in props across all items, each having an items property with all items containing that property, like this:
[{
id: 1,
name: 'one',
items : [] // array containing objects `first` and 'third'
},{
id: 2,
name: 'two',
items: [] // array containing objects `first` and 'second'
}]
I've tried various combinations inspired from answers of this question, which seems the closest I could find to what I'm trying to do.I think my real blocker is that, when trying to create an array of unique props (to which I'm going to map the items) and trying to use...
_(items).chain().flatten().pluck('props').unique().value()
... as in this answer, it tells me .chain(...).flatten(...).pluck is not a function. I also tried with .map instead of .pluck, but I guess not everything working in Underscore works in Lodash (I don't know the specific differences, I just read Lodash was forked from Underscore initially).
Note I know how to do this with classic fors and this is only an exercise. I don't have a practical use for it.
I'm just trying to learn to use lodash to its full potential. If you know how to do it, you don't even have to explain. I'll console.log() each step of the way until I understand what's going on. Also, if you think my question's name could be improved, for better indexing, considering what I want to achieve, I'm open to suggestions.
Ideally, the answer should be a chain of lodash methods, without declaring intermediary variables. I'm pretty sure it's doable (that's why I'm asking). Of course, the fewer steps the better — I assume it would impact performance in a real life scenario, but this is not a concern here — I'm aware that most times, when going for performance, the classic for loop is hard to beat.
First, let's transform each item to an array of props with the item's name, flatten this array of arrays, then the rest should be easier.
_(data)
.chain()
.flatMap(({ props, name }) => _.map(props, p => ({
id: p.id,
name: p.name,
item: name
})))
.groupBy(p => p.id)
.map(props => ({
id: _.head(props).id,
name: _.head(props).name,
items: _.map(props, p => p.item)
}))
.value();
Functional programming newbie here. I have this object:
{
_id: '2014d5db-55dc-4078-ae87-382c226d0785',
_source: {
phone: '00447827434313',
...
}
}
In the end I want to have it in this format:
{
id: '2014d5db-55dc-4078-ae87-382c226d0785',
phone: '00447827434313',
...
}
Basically extracting _source, and renaming _id to id.
I created this function below which works, but I'm trying use only Ramda's functions instead of creating new objects by hand. I assume it's more "functional" way, let me know if it doesn't really matter.
const test = o => merge(o._source, { id: o._id })
Thanks very much
I don't think there's a particular built-in Ramda function for that. But it's not hard to write one on top of lensPath, view, and map:
const remap = R.curry((desc, obj) => R.map(path => R.view(R.lensPath(path), obj), desc));
const myExtract = remap({
id: ['_id'],
phone: ['_source', 'phone']
});
myExtract(input);
//=> {"id": "2014d5db-55dc-4078-ae87-382c226d0785", "phone": "00447827434313"}
It only works this simply if your output is described as a flat list of fields (of course their properties could themselves be objects.) But one where you pulled from nested paths and pushed to nested paths would not be too much harder to write. The user API would be uglier, though, I imagine.
I don't see any clean way to make this points-free and still retain readability. Perhaps someone else might manage that, but I think this is already pretty nice.
You can see this in action on the Ramda REPL.
I'm getting to grips with using functional programming beyond a simple map or two. I have a situation where I want to be able to filter some elements from an array of objects, based on a particular field of those objects. It's a contrived example, but here goes:
I have a list of field definitions, and I want to extract two of them based on their title.
const toSearch = [
{ title: "name", description: "Their name" },
{ title: "age", description: "Their age" },
{ title: "gender", description: "Their gender" }
]
const fieldsToFind = ["name", "age"]
let filterObjects = R.map(R.objOf('title'), fieldsToFind)
let filterFuncs = R.map(R.whereEq(R.__), filterObjects)
let found = R.map(R.filter, filterFuncs)
console.log("Filter objects:", JSON.stringify(filterObjects))
console.log("Filter functions:", JSON.stringify(filterFuncs))
console.log("Found:", found[0](toSearch))
console.log("Found:", found[1](toSearch))
If I run this, the last of the output is the two elements of toSearch that I'm looking for, but it's not exactly neat. I've been trying to get another map working to get around executing found elements manually, but I also feel that even leading up to that point I'm taking an overly circuitous route.
Although it's a contrived example, is there a neater way of accomplishing this in a functional style?
One fairly simple way of doing this is:
R.filter(R.where({R.title: R.contains(R.__, ['name', 'age'])}))(toSearch);
//=> [
// {"description": "Their name", "title": "name"},
// {"description": "Their age", "title": "age"}
// ]
or, equivalently,
R.filter(R.where({title: R.flip(R.contains)(['name', 'age'])}))(toSearch);
One advantage, especially if you import the relevant functions from R into your scope, is how closely this reads to your problem domain:
var myFunc = filter(where({title: contains(__, ['name', 'age'])}));
myFunc = filter where the title contains 'name' or 'age'.
You can see this in action on the Ramda REPL.
I have a situation where I want to be able to filter some elements
from an array of objects, based on a particular field of those
objects.
For your situation, its quite simple
var filteredItems = toSearch.filter(function(value){ return fieldsToFind.indexOf(value.title) != -1 });
You could use .reduce to accomplish your task. MDN has a very brief explanation of the reduce function
I have looked everywhere for this but nobody seems to use associative arrays in objects. Here is my object:
var player = {
Level: 1,
Stats: [{Defense : 5}, {Attack: 1}, {Luck: 3}]
};
I need to access the values of Defense, Attack, and Luck, but how?
I have tried this but it hasn't worked:
player.Stats.Defense
player.Stats.Attack
player.Stats.Luck
Any ideas? Thanks!
P.S. Does it make a difference that I am using jQuery?
You've said you're in control of the structure. If so, change it to this:
var player = {
Level: 1,
Stats: {Defense : 5, Attack: 1, Luck: 3}
};
Note that Stats is now an object, not an array. Then you access that information the way you tried to, player.Stats.Defense and so on. There's no reason to make Stats an array of dissimilar objects, that just makes your life difficult.
You've used the term "associative array" which makes me think you have a PHP background. That term isn't commonly used in the JavaScript world, to avoid confusion with arrays. "Object," "map," or "dictionary" are the terms usually used, probably in that order, all referring to objects ({}). Probably nine times out of ten, if you would use an associative array for something in PHP, you'd use an object for it in JavaScript (in addition to using objects for the same sort of thing you use objects for in PHP).
P.S. Does it make a difference that I am using jQuery?
No, this is language-level rather than library-level, but it's a perfectly reasonable question.
(Making this a CW answer because it's basically what all the comments on the question are saying.)
as Stats: [{Defense : 5}, {Attack: 1}, {Luck: 3}] is array of objects, you need to do:
player.Stats[0].Defense
player.Stats[1].Attack
player.Stats[2].Luck
Here player.Stats is an array of objects. So you'll have to use index for accessing those objects.
var player = {
Level: 1,
Stats: [{Defense : 5}, {Attack: 1}, {Luck: 3}]
};
Use these :
player.Stats[0].Defense
player.Stats[1].Attack
player.Stats[2].Luck